注:这是一个常见问题的标准答案。
我有一个Spring @Service
班级( MileageFeeCalculator
)有一个 @Autowired
字段( rateService
),但这个领域 null
当我尝试使用它的时候。日志显示 MileageFeeCalculator
豆子和咖啡 MileageRateService
正在创建bean,但我得到一个 NullPointerException
每当我打电话给 mileageCharge
方法。为什么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
}
}
应该自动连线的服务bean MileageFeeCalculator
但事实并非如此:
@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)
...
16条答案
按热度按时间plicqrtu1#
已注解的字段
@Autowired
是null
因为spring不知道MileageFeeCalculator
你用它创造的new
不知道自动连线。springinversionofcontrol(ioc)容器有三个主要的逻辑组件:注册表(称为
ApplicationContext
)在可供应用程序使用的组件(bean)中,配置程序系统通过将依赖项与上下文中的bean相匹配,将对象的依赖项注入其中,以及一个依赖性求解器,它可以查看许多不同bean的配置,并确定如何按必要的顺序示例化和配置它们。ioc容器并不神奇,除非您以某种方式通知它,否则它无法了解java对象。当你打电话的时候
new
,jvm示例化新对象的一个副本并直接将其交给您--它从不经历配置过程。有三种方法可以配置bean。我已经在这个github项目中发布了所有这些代码,使用springboot启动;您可以查看每种方法的完整运行项目,以了解使其工作所需的一切。标记为
NullPointerException
:nonworking
###注射你的豆子最好的选择是让spring自动连接所有bean;这需要最少的代码量,并且是最易维护的。要使自动布线按您所希望的方式工作,还需要自动布线
MileageFeeCalculator
这样地:如果您需要为不同的请求创建服务对象的新示例,您仍然可以通过使用springbean作用域来使用注入。
通过注入
@MileageFeeCalculator
服务对象:working-inject-bean
###使用@configurable如果你真的需要用
new
要自动连线,可以使用Spring@Configurable
注解以及aspectj编译时编织来注入对象。这种方法将代码插入到对象的构造函数中,提醒spring正在创建它,以便spring可以配置新示例。这需要在构建中进行一些配置(例如使用ajc
)打开spring的运行时配置处理程序(@EnableSpringConfigured
使用javaconfig语法)。roo活动记录系统使用这种方法new
实体的示例来获取必要的持久性信息。通过使用
@Configurable
在服务对象上:working-configurable
###手动bean查找:不推荐这种方法只适用于在特殊情况下与遗留代码接口。创建一个spring可以自动连接并且遗留代码可以调用的单例适配器类几乎总是可取的,但是可以直接向spring应用程序上下文请求bean。
为此,您需要一个spring可以引用
ApplicationContext
对象:然后您的遗留代码可以调用
getContext()
检索它需要的豆子:通过在spring上下文中手动查找服务对象工作的标记:
working-manual-lookup
ru9i0ody2#
如果您没有编写web应用程序,请确保完成@autowiring的类是springbean。通常,spring容器不会知道我们可能认为是springbean的类。我们必须告诉spring容器我们的spring类。
这可以通过在appln contxt中配置来实现,或者更好的方法是将类注解为@component,请不要使用new操作符创建注解类。确保您从appln上下文中获得它,如下所示。
nwwlzxa73#
实际上,应该使用jvm托管对象或spring托管对象来调用方法。根据上面控制器类中的代码,您正在创建一个新对象来调用具有自动连接对象的服务类。
所以这样不行。
该解决方案使这个mileagefeecalculator成为控制器本身的自动连线对象。
如下所示更改控制器类。
ff29svar4#
我曾经遇到过同样的问题,当时我还不太习惯国际奥委会的生活。这个
@Autowired
我的一个bean的字段在运行时为空。根本原因是,没有使用springioc容器(其
@Autowired
场确实被正确地注入了),我是new
创建我自己的bean类型示例并使用它。当然这个是@Autowired
字段为空,因为spring没有机会注入它。zfciruhq5#
您的问题是新的(java风格的对象创建)
带注解
@Service
,@Component
,@Configuration
bean是在服务器启动时spring的应用程序上下文。但是当我们使用new操作符创建对象时,对象并没有在已经创建的应用程序上下文中注册。例如,employee.java类。
看看这个:
dfuffjeb6#
我对spring还不熟悉,但我发现了这个有效的解决方案。请告诉我这是不是一条不可取的路。
我做Spring注射
applicationContext
在这个bean中:如果需要,也可以将此代码放在主应用程序类中。
其他类可以这样使用它:
通过这种方式,任何bean都可以由应用程序中的任何对象获得(也包括
new
)以一种静态的方式。l5tcr1uw7#
这似乎很罕见,但我的遭遇如下:
我们曾经
@Inject
而不是@Autowired
这是spring支持的javaee标准。每个地方都很好,豆子注射正确,而不是一个地方。豆子注射剂似乎是一样的最后我们发现错误是我们(实际上,eclipse自动完成特性)导入的
com.opensymphony.xwork2.Inject
而不是javax.inject.Inject
!总之,请确保您的注解(
@Autowired
,@Inject
,@Service
,... ) 有正确的 Package !zbsbpyhn8#
如果在测试类中发生这种情况,请确保没有忘记对类进行注解。
例如,在spring boot中:
一段时间过去了。。。
Spring Boot继续发展。不再需要使用
@RunWith
如果您使用正确的junit版本。为了
@SpringBootTest
要独立工作,需要使用@Test
从junit5而不是junit4。如果配置错误,测试将编译,但是
@Autowired
以及@Value
字段(例如)将null
. 由于springboot是通过魔术操作的,所以您可能没有什么方法可以直接调试这个失败。tsm1rwdh9#
我认为您没有指示spring扫描带有注解的类。
你可以用
@ComponentScan("packageToScan")
在spring应用程序的配置类上,指示spring进行扫描。@Service, @Component
etc注解添加元描述。spring只注入那些创建为bean或用注解标记的类的示例。
在注入之前,用注解标记的类需要由spring识别,
@ComponentScan
指示spring查找带有注解的类。当Spring来临@Autowired
它搜索相关的bean,并注入所需的示例。只添加注解,并不能修复或促进依赖注入,spring需要知道在哪里寻找。
gorkyyrv10#
另一个解决方案是打电话:
SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this)
要像这样计算里程数:4uqofj5v11#
简单地说,这主要有两个原因
@Autowired
待处理字段null
你们班不是 Spring Bean 。田地不是豆子。
sz81bmfz12#
更新:真正聪明的人很快就指出了这个答案,这就解释了下面描述的奇怪之处
原始答案:
我不知道这是否对任何人有帮助,但即使我做的事情看起来是对的,我也会遇到同样的问题。在我的main方法中,我有这样一个代码:
在一个
token.xml
我有一句话要说我注意到package.path已经不存在了,所以我已经永远放弃了这一行。
在那之后,npe开始进来了。在一个
pep-config.xml
我只有两颗豆子:someabac类有一个声明为
由于某些未知的原因,当
<context:component-scan/>
元素根本不存在,但是当它存在并且有一些bs作为基本包时,一切都正常。这条线现在看起来像这样:而且很有效。也许有人能提供一个解释,但对我来说现在已经足够了)
klh5stk113#
这是给予nullpointerexception的罪魁祸首
MileageFeeCalculator calc = new MileageFeeCalculator();
我们使用的是spring,不需要手动创建对象。对象创建将由ioc容器负责。bbuxkriu14#
您还可以在服务类上使用@service annotation修复此问题,并将所需的bean classa作为参数传递给其他bean classb构造函数,并使用@autowired对classb的构造函数进行注解。此处是示例代码段:
ylamdve615#
本文在“执行顺序”一段中描述了这里没有提到的内容。
在“学习”了我必须用@component或派生的@service或@repository(我猜还有更多)来注解类之后,我突然想到,这些其他组件在父组件的构造函数中仍然是空的。
使用@postconstruct可以解决以下问题:
以及: