注意:这旨在成为常见问题的规范答案。
I have a Spring @Service
class ( MileageFeeCalculator
) that has an @Autowired
field ( rateService
), but the field is null
当我尝试使用它时。 The logs show that both the MileageFeeCalculator
bean and the MileageRateService
bean are being created, but I get a NullPointerException
whenever I try to call the mileageCharge
我的服务 bean 上的方法。为什么 Spring 不自动装配该字段?
控制器类:
@Controller
public class MileageFeeController {
@RequestMapping("/mileage/{miles}")
@ResponseBody
public float mileageFee(@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
}
}
应该在 MileageFeeCalculator
中自动装配的服务 bean,但它不是:
@Service
public class MileageRateService {
public float ratePerMile() {
return 0.565f;
}
}
当我尝试 GET /mileage/3
时,出现以下异常:
java.lang.NullPointerException: null
at com.chrylis.example.spring_autowired_npe.MileageFeeCalculator.mileageCharge(MileageFeeCalculator.java:13)
at com.chrylis.example.spring_autowired_npe.MileageFeeController.mileageFee(MileageFeeController.java:14)
...
原文由 chrylis -cautiouslyoptimistic- 发布,翻译遵循 CC BY-SA 4.0 许可协议
The field annotated
@Autowired
isnull
because Spring doesn’t know about the copy ofMileageFeeCalculator
that you created withnew
and didn’t知道自动装配它。Spring 控制反转 (IoC) 容器 具有三个主要的逻辑组件:一个注册表(称为
ApplicationContext
)可供应用程序使用的组件(bean),一个注入对象的配置器系统通过将依赖项与上下文中的 bean 匹配来将依赖项添加到它们中,以及可以查看许多不同 bean 的配置并确定如何以必要的顺序实例化和配置它们的依赖项解决程序。IoC 容器并不神奇,除非您以某种方式通知它,否则它无法了解 Java 对象。当您调用
new
时,JVM 会实例化新对象的副本并将其直接交给您——它永远不会完成配置过程。您可以通过三种方式配置 bean。我已经在 这个 GitHub 项目上 发布了所有这些代码,使用 Spring Boot 启动;您可以查看每种方法的完整运行项目,以查看使其工作所需的一切。 标记为
NullPointerException
:nonworking
注入你的豆子
最好的选择是让 Spring 自动装配所有 bean;这需要最少的代码并且最易于维护。为了使自动装配像你想要的那样工作,还自动装配
MileageFeeCalculator
像这样:如果您需要为不同的请求创建服务对象的新实例,您仍然可以通过使用 Spring bean 范围 来使用注入。
通过注入
@MileageFeeCalculator
服务对象工作的标签:working-inject-bean
使用@Configurable
如果您确实需要使用
new
创建的对象自动装配,您可以 使用 Spring@Configurable
注释以及 AspectJ 编译时编织 来注入您的对象。这种方法将代码插入到对象的构造函数中,提醒 Spring 它正在创建,以便 Spring 可以配置新实例。这需要在您的构建中进行一些配置(例如使用ajc
进行编译)并打开 Spring 的运行时配置处理程序(@EnableSpringConfigured
使用 JavaConfig 语法)。 Roo Active Record 系统使用此方法来允许实体的new
实例获得注入的必要持久性信息。通过在服务对象上使用
@Configurable
工作的标签:working-configurable
手动查找 bean:不推荐
这种方法仅适用于在特殊情况下与遗留代码进行交互。创建一个 Spring 可以自动装配并且遗留代码可以调用的单例适配器类几乎总是更可取的,但是可以直接向 Spring 应用程序上下文请求一个 bean。
为此,您需要一个 Spring 可以引用
ApplicationContext
对象的类:然后您的遗留代码可以调用
getContext()
并检索它需要的 beans:通过在 Spring 上下文中手动查找服务对象来工作的标签:
working-manual-lookup