iv015-spring的aop顺序和spring的循环依赖

1.spring的aop顺序

1.1Aop常用注释

  • @Before:前置通知:目标方法之前执行
  • @After:后置通知:目标方法之后执行
  • @AfterReturning:返回后通知:执行方法结束前执行(异常不执行)
  • @AfterThrowing:通知异常:出现异常时候执行
  • @Around:环绕通知:环绕目标方法执行

1.2spring4+springboot1.59/spring5+springboot2.3.3 aop执行顺序差异

2.spring的循环依赖

2.1什么是循环依赖

多个bean之间相互依赖,形成了一个闭环。比如:A依赖于B,B依赖于C,C依赖于A

通常来说,如果问spring容器内部如何解决循环依赖,一定是指默认的单例Bean中,属性互相引用的场景,也就是说,Spring的循环依赖,是Spring容器注入时候出现的问题。

2.2spring容器循环依赖报错演示BeanCurrentInCreationException

循环依赖现象在Spring容器中注入依赖的对象,有2中情况

  • 构造器方式注入依赖(构造器注入没有办法解决循环依赖,你想让构造器注入支持循环依赖,是不存在的)
  • 以set方式注入依赖

2.3spring内部通过3级缓存来解决循环依赖

只有单例的bean会通过三级缓存提前暴露来解决循环依赖的问题,而非单例的bean,每次从容器中获取都是一个新的对象,都会重新创建,所以非单例的bean是没有缓存的,不会将其放到三级缓存中。
第一级缓存:(也叫单例池)singletonObjects:存放已经经历了完整生命周期的Bean对象。
第二级缓存:earlySingletonObjects,存在早期暴露出来的Bean对象,Bean的生命周期未结束(属性还未填充完整)。
第三级缓存:Map<String,ObjectFactory<?>> singletonFactories,存放可以生成Bean的工厂。

2.4spring的循环依赖

实例化:堆内存中申请一块内存空间(租聘好房子,自己的家具东西还没有搬家进去)
初始化:完成属性的各种赋值(装修,家电家具进场)
A/B两对象在三级缓存中的迁移说明

  • A创建过程中需要B,于是将A自己放到三级缓存里面,去实例化B。
  • B实例化的时候发现需要A,于是B先查一级缓存,没有,再查二级缓存,还是没有,再查三级缓存,找到了A然后把三级缓存里面的这个A放到二级缓存里面,并删除三级缓存里面的A。
  • B顺利初始化完毕,将自己放到一级缓存里面(此时B里面的A依然是创建中状态)然后回来接着创建A,此时B已经创建结束,直接从一级缓存里面拿到B,然后完成创建,并将A自己放到一级缓存里面。

Debug断点:

Debug的步骤:

  • 1 调用doGetBean()方法,想要获取beanA,于是调用getSingleton()方法从缓存中查找beanA
  • 2 在getSingleton()方法中,从一级缓存中查找,没有,返回null
  • 3 doGetBean()方法中获取到的beanA为null,于是走对应的处理逻辑,调用getSingleton()的重载方法(参数为ObjectFactory的)
  • 4 在getSingleton()方法中,先将beanA_name添加到一个集合中,用于标记该bean正在创建中。然后回调匿名内部类的creatBean方法
  • 5 进入AbstractAutowireCapableBeanFactory#doCreateBean,先反射调用构造器创建出beanA的实例,然后判断。是否为单例、是否允许提前暴露引用(对于单例一般为true)、是否正在创建中〈即是否在第四步的集合中)。判断为true则将beanA添加到【三级缓存】中
  • 6 对beanA进行属性填充,此时检测到beanA依赖于beanB,于是开始查找beanB
  • 7 调用doGetBean()方法,和上面beanA的过程一样,到缓存中查找beanB,没有则创建,然后给beanB填充属性
  • 8 此时beanB依赖于beanA,调用getsingleton()获取beanA,依次从一级、二级、三级缓存中找,此时从三级缓存中获取到beanA的创建工厂,通过创建工厂获取到singletonObject,此时这个singletonObject指向的就是上面在doCreateBean()方法中实例化的beanA
  • 9 这样beanB就获取到了beanA的依赖,于是beanB顺利完成实例化,并将beanA从三级缓存移动到二级缓存中
  • 10 随后beanA继续他的属性填充工作,此时也获取到了beanB,beanA也随之完成了创建,回到getsingleton()方法中继续向下执行,将beanA从二级缓存移动到一级缓存中
原文地址:https://www.cnblogs.com/everyingo/p/14564975.html