zoukankan      html  css  js  c++  java
  • 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从二级缓存移动到一级缓存中
  • 相关阅读:
    程序、进程、线程区别与联系
    SQL常用知识与必须掌握的面试常问SQL语句
    快速搭建一个基于react的项目
    原生js判断设备类型
    在vue项目中设置BASE_URL
    纯前端实现数据导出excel文件
    原生js实现拖拽功能
    使用Echarts实现折线图的一点总结
    在vue项目中显示实时时间(年月日时分秒)
    在vue项目中使用MD5.js
  • 原文地址:https://www.cnblogs.com/everyingo/p/14564975.html
Copyright © 2011-2022 走看看