• Spring循环依赖-spring源码详解(四)


    上篇文章说了,bean工厂后置处理器如何加载配置类

    BeanFactoryPostProcessor-spring源码详解(三)https://blog.csdn.net/ke1ying/article/details/127543302?spm=1001.2014.3001.5501

    1. public static void loadBeanDefinitions() {
    2. RootBeanDefinition rootBeanDefinitionA = new RootBeanDefinition(InstanceA.class);
    3. RootBeanDefinition rootBeanDefinitionB = new RootBeanDefinition(InstanceB.class);
    4. beanDefinitionMap.put("instanceA", rootBeanDefinitionA);
    5. beanDefinitionMap.put("instanceB", rootBeanDefinitionB);
    6. }
    7. @Component
    8. public class InstanceA {
    9. @Autowired
    10. private InstanceB instanceB;
    11. public InstanceB getInstanceB() {
    12. return instanceB;
    13. }
    14. public void setInstanceB(InstanceB instanceB) {
    15. this.instanceB = instanceB;
    16. }
    17. public InstanceA(InstanceB instanceB) {
    18. this.instanceB = instanceB;
    19. }
    20. public InstanceA() {
    21. System.out.println("实例化A");
    22. }
    23. }

    首先把bean放入beanDefinition,之后,循环bean定义,通过bean的key来获取beanDefinition,

    通过无参构造函数反射来获取class,再赋值属性。

    1. public static void main(String[] args) throws Exception {
    2. // 加载到beanDefinition
    3. loadBeanDefinitions();
    4. for (String key : beanDefinitionMap.keySet()) {
    5. // 先创建A
    6. getBean(key);
    7. }
    8. InstanceA instanceA = (InstanceA)getBean("instanceA");
    9. System.out.println(instanceA);
    10. }
    11. private static Map singletonObjects = new ConcurrentHashMap<>();
    12. public static Object getBean(String beanName) throws Exception {
    13. Object singleton = getSingleton(beanName);
    14. if(singleton != null){
    15. return singleton;
    16. }
    17. // 实例化
    18. RootBeanDefinition rootBeanDefinition = (RootBeanDefinition) beanDefinitionMap.get(beanName);
    19. Class beanClass = rootBeanDefinition.getBeanClass();
    20. // 通过class 无参构造函数 实例化
    21. Object instanceBean = beanClass.newInstance();
    22. singletonObjects.put(beanName, instanceBean);
    23. // 属性赋值
    24. Field[] declaredFields = beanClass.getDeclaredFields();
    25. for (Field declaredField : declaredFields) {
    26. Autowired annotation = declaredField.getAnnotation(Autowired.class);
    27. // 说明bean有autowired
    28. if (annotation != null) {
    29. // 打开访问权限
    30. declaredField.setAccessible(true);
    31. // byName byType 拿到了 instanceB名字
    32. String name = declaredField.getName();
    33. // 拿到B的bean
    34. Object fileObject = getBean(name);
    35. declaredField.set(instanceBean, fileObject);
    36. }
    37. }
    38. // 初始化
    39. // 放入缓存
    40. // singletonObjects.put(beanName, instanceBean);
    41. return instanceBean;
    42. }
    43. private static Object getSingleton(String beanName) {
    44. Object singleton = singletonObjects.get(beanName);
    45. if (singleton != null) {
    46. return singleton;
    47. }
    48. return null;
    49. }

    这样写完之后,就不会有死循环,但是没有用到二级缓存,二级缓存可以用来放半成品的bean,解决多线程的情况下,多个线程同时创建bean,防止其他线程拿到不完整的bean,于是 加上二级缓存来写。

    1. private static Map<String, Object> singletonObjects = new ConcurrentHashMap<>();
    2. private static Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>();
    3. public static Object getBean(String beanName) throws Exception {
    4. Object singleton = getSingleton(beanName);
    5. if (singleton != null) {
    6. return singleton;
    7. }
    8. // 实例化
    9. RootBeanDefinition rootBeanDefinition = (RootBeanDefinition) beanDefinitionMap.get(beanName);
    10. Class<?> beanClass = rootBeanDefinition.getBeanClass();
    11. // 通过class 无参构造函数 实例化
    12. Object instanceBean = beanClass.newInstance();
    13. // 二级缓存
    14. earlySingletonObjects.put(beanName, instanceBean);
    15. // 属性赋值
    16. Field[] declaredFields = beanClass.getDeclaredFields();
    17. for (Field declaredField : declaredFields) {
    18. Autowired annotation = declaredField.getAnnotation(Autowired.class);
    19. // 说明bean有autowired
    20. if (annotation != null) {
    21. // 打开访问权限
    22. declaredField.setAccessible(true);
    23. // byName byType 拿到了 instanceB名字
    24. String name = declaredField.getName();
    25. // 拿到B的bean
    26. Object fileObject = getBean(name);
    27. declaredField.set(instanceBean, fileObject);
    28. }
    29. }
    30. // 初始化
    31. // 放入缓存
    32. singletonObjects.put(beanName, instanceBean);
    33. return instanceBean;
    34. }
    35. private static Object getSingleton(String beanName) {
    36. Object singleton = singletonObjects.get(beanName);
    37. if (singleton != null) {
    38. return singleton;
    39. }
    40. Object earlySingleton = earlySingletonObjects.get(beanName);
    41. if (earlySingleton != null) {
    42. return earlySingleton;
    43. }
    44. return null;
    45. }

    用解耦的方式,beanPostProcessor来创建动态代理。

    如果在最后调用动态代理,这时候循环依赖的bean就不是动态代理的bean,所以要在之前就创建动态代理。所以这里有两个地方调用动态代理,实例化之后和初始化之后调用。

    只在循环依赖的情况下在实例化之后创建动态代理,所以需要判断当前是不是循环依赖。

    前面一级缓存中没拿到,而二级缓存中有,才是循环依赖。

    spring源码里有一行代码,用来判断是否是循环依赖,加了一个正在创建对象的标识。

    1. private static Map singletonObjects = new ConcurrentHashMap<>();
    2. private static Map earlySingletonObjects = new ConcurrentHashMap<>();
    3. // 存放函数接口
    4. private static Map singletonFactories = new ConcurrentHashMap<>();
    5. private static Set singletonCurrennlyInCreation = new HashSet<>();
    6. public static Object getBean(String beanName) throws Exception {
    7. Object singleton = getSingleton(beanName);
    8. if (singleton != null) {
    9. return singleton;
    10. }
    11. // 正在创建
    12. if (!singletonCurrennlyInCreation.contains(beanName)) {
    13. singletonCurrennlyInCreation.add(beanName);
    14. }
    15. // 实例化
    16. RootBeanDefinition rootBeanDefinition = (RootBeanDefinition) beanDefinitionMap.get(beanName);
    17. Class beanClass = rootBeanDefinition.getBeanClass();
    18. // 通过class 无参构造函数 实例化
    19. Object instanceBean = beanClass.newInstance();
    20. // 创建动态代理
    21. // 只在循环依赖的情况下在实例化之后创建动态代理
    22. //Object o = new JDKProxyBeanPostProcessor().getEarlyBeanReference(instanceBean,beanName);
    23. /*singletonFactories.put(beanName, new ObjectFactory() {
    24. @Override
    25. public Object getObject() throws BeansException {
    26. return new JDKProxyBeanPostProcessor().getEarlyBeanReference(instanceBean,beanName);
    27. }
    28. });*/
    29. singletonFactories.put(beanName, () -> new JDKProxyBeanPostProcessor().getEarlyBeanReference(instanceBean, beanName));
    30. // 二级缓存
    31. //earlySingletonObjects.put(beanName, instanceBean);
    32. // 属性赋值
    33. Field[] declaredFields = beanClass.getDeclaredFields();
    34. for (Field declaredField : declaredFields) {
    35. Autowired annotation = declaredField.getAnnotation(Autowired.class);
    36. // 说明bean有autowired
    37. if (annotation != null) {
    38. // 打开访问权限
    39. declaredField.setAccessible(true);
    40. // byName byType 拿到了 instanceB名字
    41. String name = declaredField.getName();
    42. // 拿到B的bean
    43. Object fileObject = getBean(name);
    44. declaredField.set(instanceBean, fileObject);
    45. }
    46. }
    47. // 初始化
    48. /*if(earlySingletonObjects.containsKey(beanName)){
    49. instanceBean = earlySingletonObjects.get(beanName);
    50. }*/
    51. // 放入缓存
    52. singletonObjects.put(beanName, instanceBean);
    53. return instanceBean;
    54. }
    55. private static Object getSingleton(String beanName) {
    56. /* Object singleton = singletonObjects.get(beanName);
    57. if (singleton != null) {
    58. return singleton;
    59. }
    60. Object earlySingleton = earlySingletonObjects.get(beanName);
    61. if (earlySingleton != null) {
    62. return earlySingleton;
    63. }
    64. return null;*/
    65. Object bean = singletonObjects.get(beanName);
    66. if (bean == null && singletonCurrennlyInCreation.contains(beanName)) {
    67. // 是循环依赖
    68. bean = earlySingletonObjects.get(beanName);
    69. synchronized (singletonObjects){
    70. if(bean == null){
    71. ObjectFactory objectFactory = singletonFactories.get(beanName);
    72. if (objectFactory != null) {
    73. // 钩子函数 去创建 aop代理
    74. bean = objectFactory.getObject();
    75. earlySingletonObjects.put(beanName, bean);
    76. singletonFactories.remove(beanName);
    77. }
    78. return bean;
    79. }
    80. }
    81. }
    82. return bean;
    83. }

  • 相关阅读:
    echarts图表设置x轴y轴均随滚轮滚动缩+放 区域缩放
    【OpenPLC学习】RK3568上运行OpenPLC
    【实验技术笔记】细胞表型检测之细胞凋亡(Hoechst染色 + PI染色 + TUNEL 染色 + Annexin V-PI 双染)
    部署Nextcloud+Onlyoffice
    mysql 指定多个IP 绑定监听地址 bind_address
    SuperMap iDesktop 处理带带号坐标系的数据
    【一】Mac 本地部署大模型
    ESP8266--SDK开发(驱动WS2812B)
    挑战赛 | MagicHub中英混语音识别挑战赛发布基线系统和开发训练集
    BUUCTF-Misc20
  • 原文地址:https://blog.csdn.net/ke1ying/article/details/127626732