注释的字段@Autowired
is null
因为Spring不知道的副本MileageFeeCalculator
你用它创建的new
并且不知道自动装配它。
Spring 控制反转 (IoC) 容器 http://docs.spring.io/spring/docs/current/spring-framework-reference/html/beans.html具有三个主要逻辑组件: 注册表(称为ApplicationContext
)可供应用程序使用的组件(bean),一个配置器系统,通过将依赖关系与上下文中的bean进行匹配来将对象的依赖关系注入到它们中,以及一个依赖关系求解器,可以查看许多不同的配置beans 并确定如何按必要的顺序实例化和配置它们。
IoC 容器并不神奇,它无法了解 Java 对象,除非您以某种方式通知它。你打电话时new
,JVM 实例化新对象的副本并将其直接交给您——它从不经历配置过程。您可以通过三种方式配置 Bean。
我已经发布了所有这些代码,使用 Spring Boot 启动,位于这个 GitHub 项目 https://github.com/chrylis/spring_autowired_npe_example;您可以查看每种方法的完整运行项目,以了解使其发挥作用所需的一切。标记为NullPointerException
: nonworking https://github.com/chrylis/spring_autowired_npe_example/tree/nonworking
注入你的豆子
最可取的选择是让 Spring 自动装配所有的 beans;这需要最少的代码并且最容易维护。为了使自动装配按您想要的方式工作,还要自动装配MileageFeeCalculator
像这样:
@Controller
public class MileageFeeController {
@Autowired
private MileageFeeCalculator calc;
@RequestMapping("/mileage/{miles}")
@ResponseBody
public float mileageFee(@PathVariable int miles) {
return calc.mileageCharge(miles);
}
}
如果您需要为不同的请求创建服务对象的新实例,您仍然可以使用注入Spring bean 范围 http://docs.spring.io/spring/docs/current/spring-framework-reference/html/beans.html#beans-factory-scopes.
通过注入来工作的标签@MileageFeeCalculator
服务对象:working-inject-bean https://github.com/chrylis/spring_autowired_npe_example/tree/working-inject-bean
使用@Configurable
如果您确实需要使用创建的对象new
要自动连接,您可以使用弹簧@Configurable注释与 AspectJ 编译时编织 http://docs.spring.io/spring/docs/current/spring-framework-reference/html/aop.html#aop-atconfigurable注入你的对象。这种方法将代码插入到对象的构造函数中,提醒 Spring 它正在创建,以便 Spring 可以配置新实例。这需要在您的构建中进行一些配置(例如使用ajc
)并打开 Spring 的运行时配置处理程序(@EnableSpringConfigured
使用 JavaConfig 语法)。 Roo Active Record 系统使用此方法来允许new
您的实体的实例,以获取注入的必要持久性信息。
@Service
@Configurable
public class MileageFeeCalculator {
@Autowired
private MileageRateService rateService;
public float mileageCharge(final int miles) {
return (miles * rateService.ratePerMile());
}
}
使用的标签@Configurable
在服务对象上:working-configurable https://github.com/chrylis/spring_autowired_npe_example/tree/working-configurable
手动 bean 查找:不推荐
此方法仅适用于在特殊情况下与遗留代码进行交互。几乎总是最好创建一个 Spring 可以自动装配并且遗留代码可以调用的单例适配器类,但也可以直接向 Spring 应用程序上下文请求 bean。
为此,您需要一个 Spring 可以提供对ApplicationContext
object:
@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;
}
}
然后你的遗留代码可以调用getContext()
并检索它需要的 bean:
@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);
}
}
通过在 Spring 上下文中手动查找服务对象来工作的标签:working-manual-lookup https://github.com/chrylis/spring_autowired_npe_example/tree/working-manual-lookup