本文翻译自:Why is my Spring @Autowired field null?

Note: This is intended to be a canonical answer for a common problem. 注意:这旨在作为常见问题的规范答案。

I have a Spring @Service class ( MileageFeeCalculator ) that has an @Autowired field ( rateService ), but the field is null when I try to use it. 我有一个Spring @Service类( MileageFeeCalculator ),它具有一个@Autowired字段( rateService ),但是当我尝试使用它时,该字段为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 method on my service bean. 日志显示同时创建了MileageFeeCalculator Bean和MileageRateService Bean,但是每当尝试在服务Bean上调用mileageCharge方法时,都会收到NullPointerException Why isn't Spring autowiring the field? Spring为什么不自动接线该领域?

Controller class: 控制器类:

@Controller
public class MileageFeeController {    @RequestMapping("/mileage/{miles}")@ResponseBodypublic float mileageFee(@PathVariable int miles) {MileageFeeCalculator calc = new MileageFeeCalculator();return calc.mileageCharge(miles);}
}

Service class: 服务等级:

@Service
public class MileageFeeCalculator {@Autowiredprivate MileageRateService rateService; // <--- should be autowired, is nullpublic float mileageCharge(final int miles) {return (miles * rateService.ratePerMile()); // <--- throws NPE}
}

Service bean that should be autowired in MileageFeeCalculator but it isn't: 应该在MileageFeeCalculator自动MileageFeeCalculator服务bean,但不是:

@Service
public class MileageRateService {public float ratePerMile() {return 0.565f;}
}

When I try to GET /mileage/3 , I get this exception: 当我尝试GET /mileage/3 ,出现以下异常:

java.lang.NullPointerException: nullat com.chrylis.example.spring_autowired_npe.MileageFeeCalculator.mileageCharge(MileageFeeCalculator.java:13)at com.chrylis.example.spring_autowired_npe.MileageFeeController.mileageFee(MileageFeeController.java:14)...

#1楼

参考:https://stackoom.com/question/1LU5G/为什么我的Spring-Autowired字段为空


#2楼

The field annotated @Autowired is null because Spring doesn't know about the copy of MileageFeeCalculator that you created with new and didn't know to autowire it. 注释为@Autowired的字段为null因为Spring不知道您使用new创建的MileageFeeCalculator的副本,也不知道自动对其进行MileageFeeCalculator

The Spring Inversion of Control (IoC) container has three main logical components: a registry (called the ApplicationContext ) of components (beans) that are available to be used by the application, a configurer system that injects objects' dependencies into them by matching up the dependencies with beans in the context, and a dependency solver that can look at a configuration of many different beans and determine how to instantiate and configure them in the necessary order. Spring Inversion of Control(IoC)容器具有三个主要的逻辑组件:组件(bean)的注册表(称为ApplicationContext )可供应用程序使用,配置程序系统通过匹配将对象的依赖项注入对象上下文中具有bean的依赖关系,以及一个依赖关系求解程序,它可以查看许多不同bean的配置,并确定如何以必要的顺序实例化和配置它们。

The IoC container isn't magic, and it has no way of knowing about Java objects unless you somehow inform it of them. IoC容器不是魔术,除非您以某种方式告知Java对象,否则它无法了解Java对象。 When you call new , the JVM instantiates a copy of the new object and hands it straight to you--it never goes through the configuration process. 当您调用new ,JVM会实例化新对象的副本并将其直接交给您-它从未经历配置过程。 There are three ways that you can get your beans configured. 您可以通过三种方式配置bean。

I have posted all of this code, using Spring Boot to launch, at this GitHub project ; 我已经在GitHub项目上使用Spring Boot启动了所有这些代码; you can look at a full running project for each approach to see everything you need to make it work. 您可以针对每种方法查看一个正在运行的项目,以查看使其工作所需的一切。 Tag with the NullPointerException : nonworking 带有NullPointerException标记: nonworking

Inject your beans 注入你的豆子

The most preferable option is to let Spring autowire all of your beans; 最可取的选择是让Spring自动连接所有bean。 this requires the least amount of code and is the most maintainable. 这需要最少的代码量,并且最易于维护。 To make the autowiring work like you wanted, also autowire the MileageFeeCalculator like this: 要使自动装配工作如您所愿,还可以如下方式自动连接MileageFeeCalculator

@Controller
public class MileageFeeController {@Autowiredprivate MileageFeeCalculator calc;@RequestMapping("/mileage/{miles}")@ResponseBodypublic float mileageFee(@PathVariable int miles) {return calc.mileageCharge(miles);}
}

If you need to create a new instance of your service object for different requests, you can still use injection by using the Spring bean scopes . 如果您需要为不同的请求创建服务对象的新实例,则仍可以通过Spring bean scopes使用注入。

Tag that works by injecting the @MileageFeeCalculator service object: working-inject-bean 通过注入@MileageFeeCalculator服务对象而起作用的标记: working-inject-bean

Use @Configurable 使用@Configurable

If you really need objects created with new to be autowired, you can use the Spring @Configurable annotation along with AspectJ compile-time weaving to inject your objects. 如果确实需要自动创建使用new创建的对象,则可以使用Spring @Configurable批注以及AspectJ编译时编织来注入对象。 This approach inserts code into your object's constructor that alerts Spring that it's being created so that Spring can configure the new instance. 这种方法将代码插入到对象的构造函数中,以警告Spring正在创建它,以便Spring可以配置新实例。 This requires a bit of configuration in your build (such as compiling with ajc ) and turning on Spring's runtime configuration handlers ( @EnableSpringConfigured with the JavaConfig syntax). 这需要在构建中进行一些配置(例如,使用ajc编译)并打开Spring的运行时配置处理程序(使用JavaConfig语法的@EnableSpringConfigured )。 This approach is used by the Roo Active Record system to allow new instances of your entities to get the necessary persistence information injected. Roo Active Record系统使用这种方法来允许实体的new实例获取注入的必要持久性信息。

@Service
@Configurable
public class MileageFeeCalculator {@Autowiredprivate MileageRateService rateService;public float mileageCharge(final int miles) {return (miles * rateService.ratePerMile());}
}

Tag that works by using @Configurable on the service object: working-configurable 通过在服务对象上使用@Configurable起作用的标记: working-configurable

Manual bean lookup: not recommended 手动查找bean:不建议

This approach is suitable only for interfacing with legacy code in special situations. 这种方法仅适用于在特殊情况下与遗留代码接口。 It is nearly always preferable to create a singleton adapter class that Spring can autowire and the legacy code can call, but it is possible to directly ask the Spring application context for a bean. 几乎总是最好创建一个Spring可以自动装配并且遗留代码可以调用的Singleton适配器类,但是可以直接向Spring应用程序上下文请求一个bean。

To do this, you need a class to which Spring can give a reference to the ApplicationContext object: 为此,您需要一个Spring可以引用ApplicationContext对象的类:

@Component
public class ApplicationContextHolder implements ApplicationContextAware {private static ApplicationContext context;@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {context = applicationContext;   }public static ApplicationContext getContext() {return context;}
}

Then your legacy code can call getContext() and retrieve the beans it needs: 然后,您的旧代码可以调用getContext()并检索所需的bean:

@Controller
public class MileageFeeController {    @RequestMapping("/mileage/{miles}")@ResponseBodypublic float mileageFee(@PathVariable int miles) {MileageFeeCalculator calc = ApplicationContextHolder.getContext().getBean(MileageFeeCalculator.class);return calc.mileageCharge(miles);}
}

Tag that works by manually looking up the service object in the Spring context: working-manual-lookup 通过在Spring上下文中working-manual-lookup服务对象而起作用的标记: working-manual-lookup


#3楼

If you are not coding a web application, make sure your class in which @Autowiring is done is a spring bean. 如果您不编写Web应用程序的代码,请确保完成@Autowiring的类是spring bean。 Typically, spring container won't be aware of the class which we might think of as a spring bean. 通常,spring容器不会意识到我们可能将其视为spring bean的类。 We have to tell the Spring container about our spring classes. 我们必须告诉Spring容器我们的Spring类。

This can be achieved by configuring in appln-contxt or the better way is to annotate class as @Component and please do not create the annotated class using new operator. 这可以通过在appln-contxt中配置来实现,或者更好的方法是将类注释为@Component ,请不要使用new运算符创建带注释的类。 Make sure you get it from Appln-context as below. 确保从Appln上下文中获取它,如下所示。

@Component
public class MyDemo {@Autowiredprivate MyService  myService; /*** @param args*/public static void main(String[] args) {// TODO Auto-generated method stubSystem.out.println("test");ApplicationContext ctx=new ClassPathXmlApplicationContext("spring.xml");System.out.println("ctx>>"+ctx);Customer c1=null;MyDemo myDemo=ctx.getBean(MyDemo.class);System.out.println(myDemo);myDemo.callService(ctx);}public void callService(ApplicationContext ctx) {// TODO Auto-generated method stubSystem.out.println("---callService---");System.out.println(myService);myService.callMydao();}}

#4楼

Another solution would be putting call: SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this) 另一个解决方案是调用: SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this)
To MileageFeeCalculator constructor like this: 对于MileageFeeCalculator构造函数,如下所示:

@Service
public class MileageFeeCalculator {@Autowiredprivate MileageRateService rateService; // <--- will be autowired when constructor is calledpublic MileageFeeCalculator() {SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this)}public float mileageCharge(final int miles) {return (miles * rateService.ratePerMile()); }
}

#5楼

I'm new to Spring, but I discovered this working solution. 我是Spring的新手,但是我发现了这个可行的解决方案。 Please tell me if it's a deprecable way. 请告诉我这是否是可弃的方法。

I make Spring inject applicationContext in this bean: 我在这个bean中使Spring注入applicationContext

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;@Component
public class SpringUtils {public static ApplicationContext ctx;/*** Make Spring inject the application context* and save it on a static variable,* so that it can be accessed from any point in the application. */@Autowiredprivate void setApplicationContext(ApplicationContext applicationContext) {ctx = applicationContext;       }
}

You can put this code also in the main application class if you want. 如果需要,您也可以将此代码放入主应用程序类。

Other classes can use it like this: 其他类可以这样使用它:

MyBean myBean = (MyBean)SpringUtils.ctx.getBean(MyBean.class);

In this way any bean can be obtained by any object in the application (also intantiated with new ) and in a static way . 这样,应用程序中的任何对象 (也可以通过new实例化) 都可以以静态方式 获取任何bean


#6楼

Your problem is new (object creation in java style) 您的问题是新的(以Java风格创建对象)

MileageFeeCalculator calc = new MileageFeeCalculator();

With annotation @Service , @Component , @Configuration beans are created in the 使用注解@Service @Component@Service@Component @Configuration Bean在
application context of Spring when server is started. 服务器启动时Spring的应用程序上下文。 But when we create objects using new operator the object is not registered in application context which is already created. 但是,当我们使用new运算符创建对象时,该对象未在已创建的应用程序上下文中注册。 For Example Employee.java class i have used. 例如我使用的Employee.java类。

Check this out: 看一下这个:

public class ConfiguredTenantScopedBeanProcessor implements BeanFactoryPostProcessor {@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {String name = "tenant";System.out.println("Bean factory post processor is initialized"); beanFactory.registerScope("employee", new Employee());Assert.state(beanFactory instanceof BeanDefinitionRegistry,"BeanFactory was not a BeanDefinitionRegistry, so CustomScope cannot be used.");BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;for (String beanName : beanFactory.getBeanDefinitionNames()) {BeanDefinition definition = beanFactory.getBeanDefinition(beanName);if (name.equals(definition.getScope())) {BeanDefinitionHolder proxyHolder = ScopedProxyUtils.createScopedProxy(new BeanDefinitionHolder(definition, beanName), registry, true);registry.registerBeanDefinition(beanName, proxyHolder.getBeanDefinition());}}
}}

为什么我的Spring @Autowired字段为空?相关推荐

  1. springboot反射执行private方法@Autowired字段为空

    springboot反射执行private方法@Autowired字段为空 描述 错误复现 controller service ReflectServiceImpl ReflectCallServi ...

  2. java 字段为空设置默认值_java – 当字段为空时使用MyBatis添加默认值

    当我的字段为空时,我想从数据库中插入默认值.我使用的是Oracle数据库. CREATE TABLE "EMPLOYEE" ("COL1" VARCHAR2(8 ...

  3. Wiring in Spring: @Autowired, @Resource and @Inject 三种注解实现依赖注入

    原文链接:Wiring in Spring: @Autowired, @Resource and @Inject 1. Overview 概述 In this Spring Framework tut ...

  4. oracle判断非空并拼接,oracle sql 判断字段非空,数据不重复,插入多跳数据

     oracle sql 判断字段非空,数据不重复 select distinct(mobile) from wx_user_mobile where active_time is not null ...

  5. php获取longtext字段为空,php – 在longtext字段上准备好的mysqli select语句将返回空...

    我有一个运行良好的数据库查询功能 – 除了我遇到了 mysqli预处理语句和longtext字段显然已知的问题.即使通过phpMyAdmin运行查询工作正常,longtext字段总是空的,会发生什么. ...

  6. Spring @Autowired、@Resource、@Required、@Component、@Repository、@Service、@Controller注解的用法和作用...

    Spring @Autowired,@Resource,@Required注解的用法和作用 Spring中 @Autowired标签与 @Resource标签 的区别 Spring注解@Compone ...

  7. mysql中判断字段为空

    mysql中判断字段为null或者不为null 在mysql中,查询某字段为空时,切记不可用 = null, 而是 is null,不为空则是 is not null select nulcolumn ...

  8. spring autowired idea都匹配上了_你清楚这几个Spring常用注解吗?

    作者:平凡希http://cnblogs.com/xiaoxi/p/5935009.html 传统的Spring做法是使用.xml文件来对bean进行注入或者是配置aop.事物,这么做有两个缺点: 如 ...

  9. Json转换值类型字段为空字符串时报错问题

    1.问题 在写Webservices时,碰到的问题. 定义的类: 1 public class User 2 { 3 public string sID { get; set; } 4 public ...

最新文章

  1. 小工匠聊架构 - 构建架构思维
  2. CoDeSys的前世今生
  3. 用subline添加单引号和逗号,在sql中使用
  4. react性能优化方案_React灵敏且性能卓越的Spray + Akka解决方案,以“在Java和Node.js中发挥并发性和性能”...
  5. VS2010 快捷键 (空格显示 绿点, Tab 显示箭头)
  6. 怎么提升笔记本显卡性能
  7. linux动态调试工具od,OllyDBG(OD动态调试工具)
  8. 郝斌老师C语言视频观感
  9. 【转】D3DXLoadSkinMeshFromXof函数及.x在不同dx版本中
  10. 2021年河南省中等职业教育技能大赛 网络搭建与应用项目
  11. 发票识别OCR和发票扫描仪
  12. 【聚来宝】创业 兼职 教程 资料
  13. 十大最佳外国Android游戏下载平台
  14. Camtasia Studio 录制视频保存为camrec格式后快速导出为AVI格式
  15. 看网易云公开课代码性能开发有感,怎样提高代码的性能
  16. Commander(指挥官)介绍
  17. 手动实现一年12个月的工作日日历
  18. js设置页面语音播放
  19. gpib linux 驱动下载,自动化测试—GPIB工具实现
  20. React入门小册(三)组件

热门文章

  1. CLOSE_WAIT状态的原因与解决方法(2)
  2. atitit.激活一个窗口总结 swing java .net php
  3. 一下删除MSSQL表所有的数据,但不删除表结构
  4. 3G应用需要所有的网友共同创造
  5. Oracle数据库执行Sql脚本
  6. django高级应用(分页功能)
  7. 读《那些年,那些事 一个程序猿的奋斗史》 一点自己的感触
  8. Microsoft Word 段前距设置和页眉设置
  9. System center virtual machine manager 2008 R2安装部署
  10. 一个nginx 502问题解决方案