注意:这是针对常见问题的规范答案 .
我有一个 @Service
类( MileageFeeCalculator
),它有一个 @Autowired
字段( rateService
),但当我尝试使用它时,该字段为 null
. 日志显示正在创建 MileageFeeCalculator
bean和 MileageRateService
bean,但每当我尝试在服务bean上调用 mileageCharge
方法时,我得到 NullPointerException
. 为什么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)
...
12 回答
当我不习惯
the life in the IoC world
时,我曾经遇到过同样的问题 . 我的一个bean的@Autowired
字段在运行时为null .根本原因是,我没有使用由Spring IoC容器(其
@Autowired
字段正确注入indeed
)维护的自动创建的bean,而是我自己的bean类型的实例并使用它 . 当然这个@Autowired
字段是空的,因为Spring没有机会注入它 .如果在测试类中发生这种情况,请确保您没有忘记注释该类 .
例如,在_565156中:
注释
@Autowired
的字段是null
,因为Spring不知道您使用new
创建的MileageFeeCalculator
的副本,并且不知道自动装配它 .The Spring Inversion of Control (IoC) container有三个主要的逻辑组件:一个可供应用程序使用的组件(bean)的注册表(称为
ApplicationContext
),一个配置器系统,通过将依赖项与上下文中的bean相匹配,将对象的依赖项注入其中,和依赖项求解器,可以查看许多不同bean的配置,并确定如何以必要的顺序实例化和配置它们 .IoC容器并不神奇,除非你以某种方式告知它们,否则它无法知道Java对象 . 当您调用
new
时,JVM会实例化新对象的副本并直接交给您 - 它永远不会经历配置过程 . 您可以通过三种方式配置Bean .我发布了所有这些代码,使用Spring Boot启动,在this GitHub project;您可以查看每个方法的完整运行项目,以查看使其工作所需的一切 . Tag with the NullPointerException: nonworking
注入你的 beans 子
最可取的选择是让Spring自动装配所有bean;这需要最少量的代码,并且是最易于维护的 . 要使自动装配工作符合您的要求,也可以像这样自动装配
MileageFeeCalculator
:如果需要为不同的请求创建服务对象的新实例,仍可以使用the Spring bean scopes进行注入 .
Tag that works by injecting the @MileageFeeCalculator service object: working-inject-bean
使用@Configurable
如果您确实需要使用
new
创建的对象进行自动装配,则可以use the Spring @Configurable annotation along with AspectJ compile-time weaving注入您的对象 . 此方法将代码插入到正在创建的对象_565096中,以便Spring可以配置新实例 . 这需要在构建中进行一些配置(例如使用ajc
进行编译)并启用Spring的运行时配置处理程序(带有JavaConfig语法的@EnableSpringConfigured
) . Roo Active Record系统使用此方法允许实体的new
实例获取注入的必要持久性信息 .Tag that works by using @Configurable on the service object: working-configurable
手动bean查找:不推荐
此方法仅适用于在特殊情况下与遗留代码进行交互 . 创建一个Spring可以自动装配并且遗留代码可以调用的单例适配器类几乎总是更可取,但是可以直接向Spring应用程序上下文询问bean .
要做到这一点,你需要一个类可以向Spring提供对
ApplicationContext
对象的引用:然后您的遗留代码可以调用
getContext()
并检索所需的bean:Tag that works by manually looking up the service object in the Spring context: working-manual-lookup
如果您没有编写Web应用程序的代码,请确保完成@Autowiring的类是一个spring bean . 通常,spring容器不会意识到我们可能认为是一个spring bean的类 . 我们必须告诉Spring容器我们的spring类 .
这可以通过在appln-contxt中配置来实现,或者 the better way 是将类注释为 @Component 并且请不要使用new运算符创建带注释的类 . 确保从Appln上下文中获取它,如下所示 .
实际上,您应该使用JVM托管对象或Spring托管对象来调用方法 . 从控制器类中的上述代码中,您将创建一个新对象来调用具有自动连接对象的服务类 .
所以它不会那样工作 .
该解决方案使此MileageFeeCalculator成为Controller本身的自动连线对象 .
像下面一样更改您的Controller类 .
你的问题是新的(java风格的对象创建)
使用注释
@Service
,@Component
,@Configuration
bean在中创建服务器启动时Spring的应用程序上下文 . 但是当我们使用new运算符创建对象时该对象未在已创建的应用程序上下文中注册 . 我使用的示例Employee.java类 .
看一下这个:
这似乎是罕见的情况,但这是发生在我身上的事情:
我们使用
@Inject
而不是@Autowired
这是Spring支持的javaee标准 . 每个地方都运转良好, beans 子正确注入,而不是一个地方 . beans 注射似乎是一样的最后我们发现错误是我们(实际上,Eclipse自动完成功能)导入
com.opensymphony.xwork2.Inject
而不是javax.inject.Inject
!总而言之,请确保您的注释(
@Autowired
,@Inject
,@Service
,...)具有正确的包!我'm new to Spring, but I discovered this working solution. Please tell me if it'是一种不可改变的方式 .
我在这个bean中使用Spring注入
applicationContext
:如果需要,您也可以将此代码放在主应用程序类中 .
其他类可以像这样使用它:
这样 any bean can be obtained by any object in the application (也用
new
实例化)和 in a static way .我想你错过了指示spring用注释扫描类 .
您可以在spring应用程序的配置类上使用
@ComponentScan("packageToScan")
来指示spring扫描 .@Service, @Component
etc annotations添加元描述 .Spring只注入那些创建为bean或用注释标记的类的实例 .
标有注释的类需要在注入之前通过spring标识,
@ComponentScan
指示spring查找标有注释的类 . 当Spring找到@Autowired
时,它会搜索相关的bean,并注入所需的实例 .仅添加注释,不能修复或促进依赖注入,Spring需要知道在哪里寻找 .
另一种解决方案是拨打电话:
SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this)
对于MileageFeeCalculator构造函数,如下所示:
您还可以使用服务类上的@Service注释修复此问题,并将所需的bean classA作为参数传递给其他beans classB构造函数,并使用@Autowired注释classB的构造函数 . 此处的示例代码段:
UPDATE: 真聪明的人很快就指出this答案,这解释了古怪,如下所述
ORIGINAL ANSWER:
我不知道它是否对任何人都有帮助,但即使在看似正确的事情上我也遇到了同样的问题 . 在我的Main方法中,我有一个这样的代码:
在一个
token.xml
文件中,我有一条线我注意到package.path不再存在,所以我只是放弃了这条线 .
之后,NPE开始进入 . 在
pep-config.xml
我只有2个 beans 子:和SomeAbac类有一个声明为的属性
由于某些未知原因,init()中的设置为null,当
<context:component-scan/>
元素根本不存在时,但当它存在并且有一些bs作为basePackage时,一切都运行良好 . 这条线现在看起来像这样:它的工作原理 . 可能有人可以提供解释,但对我而言,现在就足够了)