第十三周_R- Why is my Spring @Autowired field null?

140 阅读1分钟

stackoverflow.com/questions/1…

背景

@Controller
    public class MileeageFeeController {

        @RequestMapping("mileage/{miles}")
        @ResponseBody
        public float mileeageFee(@PathVariable int miles) {
            MileageFeeCalculator calc = new MileageFeeCalculator();
            return calc.mileageCharge(miles);
        }

    }
@Service
    public class MileageFeeCalculator {
        @Autowired
        private MileageRateService rateService; // <--- should be autowired, is null

        public float mileageCharge(final int miles) {
            return (miles * rateService.ratePerMile()); // <--- throws NPE
        }
    }
@Service
    public class MileageRateService {
        public float ratePerMile() {
            return 0.565f;
        }
    }

上面的代码会报出空指针。

高赞回答

注解@Autowired的字段是空的,因为Spring不知道你用new创建的MileageFeeCalculator的副本,也不知道要自动连接它。

Spring IOC 容器有三个主要的逻辑组件:一个可供应用程序使用的组件(Bean)的注册表(ApplicationContext),一个通过将依赖关系与上下文中的 Bean 相匹配而将对象的依赖关系注入其中的 configurer 系统,以及一个可以查看许多不同 Bean 的配置并确定如何以必要的顺序实例化和配置它们的依赖解决器。

IoC容器并不是魔法,它没有办法知道 Java 对象,除非你以某种方式通知它。当你调用 new 时,JVM 会实例化一个新对象的副本并直接交给你--它从不经过配置过程。有三种方法可以让你的 bean 得到配置。

注入你的 bean

直接将类全部交给 IoC 管理即可

@Controller
public class MileageFeeController {

    @Autowired
    private MileageFeeCalculator calc;

    @RequestMapping("/mileage/{miles}")
    @ResponseBody
    public float mileageFee(@PathVariable int miles) {
        return calc.mileageCharge(miles);
    }
}

Manual bean lookup: not recommended

@Component
public class ApplicationContextHolder implements ApplicationContextAware {
    private static ApplicationContext context;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        context = applicationContext;   
    }

    public static ApplicationContext getContext() {
        return context;
    }
}
@Controller
public class MileageFeeController {    
    @RequestMapping("/mileage/{miles}")
    @ResponseBody
    public float mileageFee(@PathVariable int miles) {
        MileageFeeCalculator calc = ApplicationContextHolder.getContext().getBean(MileageFeeCalculator.class);
        return calc.mileageCharge(miles);
    }
}

其中还有一种使用 Configurable 注解,不过本地没有复现。猜测可能和版本有关。