gpt4 book ai didi

java - 为什么我的 Spring @Autowired 字段为空?

转载 作者:行者123 更新时间:2023-12-01 18:00:42 25 4
gpt4 key购买 nike

注意:这是针对常见问题的规范答案。

我有一个 Spring @Service 类 (MileageFeeCalculator),它有一个 @Autowired 字段 (rateService) ,但当我尝试使用它时,该字段为 null 。日志显示 MileageFeeCalculator bean 和 MileageRateService bean 均已创建,但每当我尝试调用 时,都会收到 NullPointerException我的服务 bean 上的 >mileageCharge 方法。为什么 Spring 不 Autowiring 该字段?

Controller 类:

@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
}
}

服务 bean 应该在 MileageFeeCalculator 中 Autowiring ,但事实并非如此:

@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)
...

最佳答案

注释为 @Autowired 的字段为 null,因为 Spring 不知道您使用 new 创建的 MileageFeeCalculator 的副本 并且不知道如何 Autowiring 它。

The Spring Inversion of Control (IoC) container具有三个主要逻辑组件:可供应用程序使用的组件(bean)的注册表(称为 ApplicationContext)、配置器系统,通过匹配依赖关系将对象的依赖关系注入(inject)到对象中上下文中包含 bean,以及一个依赖关系求解器,它可以查看许多不同 bean 的配置并确定如何按必要的顺序实例化和配置它们。

IoC 容器并不神奇,它无法了解 Java 对象,除非您以某种方式通知它。当您调用 new 时,JVM 会实例化新对象的副本并将其直接交给您 - 它永远不会经历配置过程。您可以通过三种方式配置 Bean。

我已使用 Spring Boot 发布了所有这些代码,地址为 this GitHub project ;您可以查看每种方法的完整运行项目,以了解使其发挥作用所需的一切。 带有 NullPointerException 的标记:nonworking

注入(inject)你的bean

最好的选择是让 Spring Autowiring 所有的 beans;这需要最少的代码并且最容易维护。为了使 Autowiring 按照您想要的方式工作,还可以像这样 Autowiring MileageFeeCalculator:

@Controller
public class MileageFeeController {

@Autowired
private MileageFeeCalculator calc;

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

如果您需要为不同的请求创建服务对象的新实例,您仍然可以使用 the Spring bean scopes 来使用注入(inject).

通过注入(inject)@MileageFeeCalculator服务对象来工作的标签:working-inject-bean

使用@Configurable

如果您确实需要使用 new 创建的对象进行 Autowiring ,您可以 use the Spring @Configurable annotation along with AspectJ compile-time weaving注入(inject)你的对象。这种方法将代码插入到对象的构造函数中,提醒 Spring 它正在创建,以便 Spring 可以配置新实例。这需要在构建中进行一些配置(例如使用ajc进行编译)并打开Spring的运行时配置处理程序(使用JavaConfig语法的@EnableSpringConfigured)。 Roo Active Record 系统使用此方法来允许实体的新实例获取注入(inject)的必要持久性信息。

@Service
@Configurable
public class MileageFeeCalculator {

@Autowired
private MileageRateService rateService;

public float mileageCharge(final int miles) {
return (miles * rateService.ratePerMile());
}
}

通过在服务对象上使用 @Configurable 来工作的标记:working-configurable

手动 Bean 查找:不推荐

此方法仅适用于在特殊情况下与遗留代码交互。几乎总是最好创建一个 Spring 可以 Autowiring 并且遗留代码可以调用的单例适配器类,但也可以直接向 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

关于java - 为什么我的 Spring @Autowired 字段为空?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60637658/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com