注释该字段 @Autowired
是 null
因为 Spring 不知道 MileageFeeCalculator
您创建的 new
,也不知道如何自动连接它。
Spring 控制反转 (IoC) 容器 有三个主要逻辑组件:一个 ApplicationContext
可供应用程序使用的组件 (bean) 的注册表 (称为 ),一个通过将依赖项与上下文中的 bean 匹配来向对象注入对象依赖项的配置器系统,以及一个依赖项解析器,它可以查看许多不同 bean 的配置并确定如何以必要的顺序实例化和配置它们。
IoC 容器并不神奇,除非您以某种方式通知它,否则它无法了解 Java 对象。当您调用 时 new
,JVM 会实例化新对象的副本并将其直接交给您 - 它从不经过配置过程。有三种方法可以配置您的 bean。
我已经将所有这些代码(使用 Spring Boot 启动)发布到 这个 GitHub 项目 ;您可以查看每种方法的完整运行项目,以了解使其工作所需的一切。 Tag with the NullPointerException
: nonworking
注入 bean
最可取的选项是让 Spring 自动装配所有 bean;这需要的代码量最少,并且最易于维护。要使自动装配按您的需要工作,还可以像这样自动装配 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 作用域 .
通过注入@MileageFeeCalculator 服务对象起作用的标签:working-inject-bean
使用 @Configurable
如果您确实需要使用 创建的对象 new
自动装配,则可以 use the Spring @Configurable
annotation along with AspectJ compile-time weaving 来注入对象。此方法将代码插入对象的构造函数中,以提醒 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
手动 bean 查找:不推荐
这种方法只适用于在特殊情况下与遗留代码交互。创建一个 Spring 可以自动装配并且遗留代码可以调用的单例适配器类几乎总是更好的选择,但也可以直接向 Spring 应用程序上下文请求 bean。
为此,您需要一个 Spring 可以为其提供对象引用的类 ApplicationContext
:
@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