关于@Autowired后Spring无法注入的问题

在使用Spring框架开发的时候,难免有时会遇到@Autowired后无法自动主动,然后报空指针异常的错,下面说一下本人遇到的问题和解决办法.

1.对于新手来说,最明显的不过是在applicationContext.xml文件上没有加<context:component-scan base-package="com.xxx"/>,或者明明写了,但Spring还是没有将该类注入到容器中.其实,很多人都喜欢将包的路径写的非常的详细,比如:com.xxx.xxx.service等,这样做的好处是Spring启动的时候,扫描的类更少了,效率更高了.这样做其实无可厚非,但是有些时候,你难免会把所有需要交给Spring管理都放在这个包下,这就导致有些放在其它包下的,贴有@Controller,@Service,@Repository,@Component等注解的类也不会交给Spring管理了.所以,最稳妥的方法就是,扫描所有的包,如下


2.主要说一下本人最近遇到的一个比较常识性但又容易踩坑的地方,我们都知道,如果你想要通过@Autowired注入一个对象,那么前提是当前你所在的这个类本身需要被Spring管理, 举个例子: 你想要在一个Controller里注入一个Service,那么不仅这个Service要贴上@Service,这个Controller也要贴上@Controller, 如果当前的Controller并未贴上@Controller,那就无法注入,因为Spring并未管理当前Controller的生命周期.

重点来了,如果我的一个Service A明明已经贴上了注解,另一个Service B也贴上了注解,而且都被扫描到了,那为什么还是无法通过@Autowired注入呢?

原理其实很简单, 在SMSImpl里要调用receiptService的方法,首先SMSImpl这个类就要从容器中拿,而不能直接new出来,因为交给Spring管理的类一般默认是单例的,它会为这个对象注入属性,但自己new出来的类,就不会注入这个属性了,而我拿到的SMSImpl实现类其实就是我自己new出来的.

 

2.探讨Spring注解@Autowired属性注入、设值注入和构造注入的注入时机

相信大家在使用Spring进行开发的时候,肯定都使用过Spring的注解@Autowired来自动注入获取Bean。这里我们就简单的探讨一下一个小问题,一个之前被我忽略掉的问题:@Autowired属性注入,设值注入和构造注入的注入时机

提问阶段

@Autowired属性注入,设值注入和构造注入的注入 谁是最终生效者?他们之间的执行顺序是怎么样的?注入时机在什么阶段?

问题
我们都使用过@Autowired的三种注入方式

属性注入
设值注入
构造注入
但是你有没有想过如果我在同一个类中,对某个成员属性用三种方式分别注入,那么最后这个属性获取的Bean是哪种方式注入的呢?

又或者说,我们都知道有三种方式可以进行依赖注入,那么这三种方式在注入的时机有和不同呢?他们之间的注入顺序是怎么样的呢?


验证阶段


从提问阶段可以知道,我们总共需要解决两个问题:
首先验证一个猜想

    在同一个类中,分别对同一个成员属性进行三种方式的依赖注入,最后的注入结果是哪种方式注入的?

同时要了解

      属性注入、设值注入和构造注入的注入时机分别是什么?他们的执行顺序是怎么样的?
 

第一步: 首先我们定义一个接口和三个实现类

Hello接口


Hello1实现类


Hello2实现类


Hello3实现类


接口是用于做静态类型去实现多态的,每个实现类都有自己的名称name,用于最后确认接口最后被注入的Bean是哪个一个

第二步: 编写测试类HelloTest
/**
 * 测试类
 */

  

测试类中实现的就是用三种方式都依赖注入Hello接口的实例,看看最后init(),use()方法中输出的hello对象是哪一个实现类的实例

属性注入对应Hello1
构造注入对应Hello2
设值注入对应Hello3
第三步: 编写Bean的后置处理器,从Bean的生命周期角度观察
MyInstantiationAwareBeanPostProcessor类

 

对Bean的生命周期不熟的可以先看这里,我这里就简单说明一下

InstantiationAwareBeanPostProcessor是一个Bean的后置处理器,我这里共实现了它的三个方法,三个方法都有自己的功能,我们可以把这个类简单理解成是Bean创建过程中的拦截器

postProcessBeforeInstantiation 在Bean要实例化前拦截到
postProcessAfterInstantiation 在Bean实例化后拦截
postProcessProperties则是在Bean填充属性阶段前拦截
总之,在我们这里的目的就是,分别输出Hello1,Hello2,Hello3三个Bean的实例化前,实例化后,实例化时,填充属性前的执行时刻,记录出他们的执行顺序是怎么样?


第四步: SpringBoot启动类启动

启动SpringBoot引导类,并在init方法中调用测试类的use方法

输出结果

结论阶段

结论一

我们可以看到HelloTest测试类的init方法和use方法输出的Hello实例都是Hello3;

所以从输出的结果中,我们可以得出结论:

  • 成员属性经过属性注入,构造注入和设值注入之后,最终的结果是设值注入的Bean

    结论二

    属性注入,构造注入,设值注入的注入时机分析:

  • 最终结论
    所以最终的结论就是:

    如果三种注入方式都被使用了,最终生效的是设值注入; 他们之间的顺序是 构造注入 > 属性注入 > 设值注入

    构造注入发生在Bean生命周期的实例化阶段,不是发生在填充属性阶段

    属性注入和设值注入都是发生在Bean生命周期的填充属性阶段,且属性注入发生在设置注入之前

 

3. 注解注入和 xml注入谁先完成?

 

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值