Spring之Bean自注入问题之@Autowired进来的Bean为null <=== 循环依赖大致处理过程

        使用spring事务时,需要调用自身的其他方法,通常使用自注入解决问题。这种方式处理起来简单方便,如果自注入后再要用这个bean中普通方法再调用注入的bean,会报空指针异常!

@Autowired field方式注入,属性注入

@Resource 和 @Autowired的区别:

  • 都是用来自动装配的,都放在属性字段上
  • @Autowired 通过byType的方式实现,而且必须要求这个对象存在!【常用】
  • @Resource 默认通过byname的方式实现,如果找不到名字,则通过byType实现!如果两个都找不到的情况下,就报错!【常用】
  • 执行顺序不同:@Autowired 通过byType的方式实现。@Resource 默认通过byname的方式实现。

Spring之Bean自注入问题之@Autowired进来的Bean为null <=== 循环依赖大致处理过程_第1张图片

 构造注入,无法解决循环依赖问题!<=== Bean实例化失败,无法进入第二步填充属性。

构造函数注入,可以提前更早的发现循环依赖!

// setter方式注入

// 1.定义成员变量
private MyBean myBean;

// 2.setter 注入
@Autowired
public void setMyBean(MyBean myBean) {
    this.myBean = myBean;
}

循环问题解决时机

Spring之Bean自注入问题之@Autowired进来的Bean为null <=== 循环依赖大致处理过程_第2张图片

 spring解决单例模式下循环依赖

Spring之Bean自注入问题之@Autowired进来的Bean为null <=== 循环依赖大致处理过程_第3张图片

A.class与B.class相互依赖,形成循环依赖

1. A实例化自己的时候发现自己依赖B,会先将自己放入三级缓存,先去实例化B

2.B实例化的时候发现发现自己依赖A,先去查一级缓存,没有,接着去二级缓存查,还没有,再去查三级缓存,找到。然后将三级缓存中的A放入二级缓存,并删掉三级缓存中的A。此时B完成自己的实例化。然后把自己放入一级缓存中,同时删除二级缓存中的自己。

3.再去实例化A,A再去查一级缓存,完成自己的实例化,然后把自己放入一级缓存中,同时删除三级缓存中的自己。

4.完成1、2、3后完成各自的实例化。

循环依赖,原型模式会怎样?

Bean加上注解 @Scope(BeanDefinition.SCOPE_PROTOTYPE)

无法提前暴露,因为每次都new新的Bean!!!

Spring之Bean自注入问题之@Autowired进来的Bean为null <=== 循环依赖大致处理过程_第4张图片

@SpringBootApplication
@Import({ServiceA.class, ConfigurationA.class, BeanB.class})
public class TestApplication {
    public static void main(String[] args) {
        SpringApplication.run(TestApplication.class, args);
    }
}

   @Import扫描Bean是为了方便指定Bean的初始化顺序。Spring会按照@Import的顺序依次加载Bean。同时,在加载每个Bean的时候,如果这个Bean有需要注入的依赖,则会试图加载他依赖的Bean。

先加载BeanA

  1. 当Spring在试图加载ServiceA时,先构造了ServiceA,然后发现他依赖BeanA,于是就试图去加载BeanA;
  2. Spring想构造BeanA,但是发现BeanA在ConfigurationA内部,于是又试图加载ConfigurationA(此时BeanA仍未构造);
  3. Spring构造了ConfigurationA的实例,然后发现他依赖BeanB,于是就试图去加载BeanB。
  4. Spring构造了BeanB的实例,然后发现他依赖BeanA,于是就试图去加载BeanA。
  5. Spring发现BeanA还没有实例化,此时Spring发现自己回到了步骤2。。。GG。。。

先加载BeanB

  1. 当Spring在试图加载ServiceA时,先构造了ServiceA,然后发现他依赖BeanB,于是就试图去加载BeanB;
  2. Spring构造了BeanB的实例,然后发现他依赖BeanA,于是就试图去加载BeanA。
  3. Spring发现BeanA在ConfigurationA内部,于是试图加载ConfigurationA(此时BeanA仍未构造);
  4. Spring构造了ConfigurationA的实例,然后发现他依赖BeanB,并且BeanB的实例已经有了,于是将这个依赖填充进ConfigurationA中。
  5. Spring发现ConfigurationA已经完成了构造、填充了依赖,于是想起来构造了BeanA。
  6. Spring发现BeanA已经有了实例,于是将他给了BeanB,BeanB填充的依赖完成。
  7. Spring回到了为ServiceA填充依赖的过程,发现还依赖BeanA,于是将BeanA填充给了ServiceA。
  8. Spring成功完成了初始化操作。

再来看,自己注入自己,然后再使用自己注入自己的这个代理类,普通方法未被代理。。。

自注入后异步也会出问题!

你可能感兴趣的:(杂记和踩坑,Bean自注入)