Spring循环依赖-实践&三级缓存的再次理解

Spring循环依赖流程图

很早之前阅读源码写过总结:
https://github.com/doctording/spring-framework-5.1.3.RELEASE/blob/dev/docs/doc/bean/dependency.md

A,B相互依赖的创建流程即如下图所示:
在这里插入图片描述

场景:A 依赖B; B依赖A、C; C依赖A

A --> B
B --> A, C
C --> A

A,B, C三个类的定义

A

package com4;

public class A {
    
    
    private B b;

    public B getB() {
    
    
        return b;
    }

    public void setB(B b) {
    
    
        this.b = b;
    }
}

B

package com4;

public class B {
    
    
    private A a;

    public A getA() {
    
    
        return a;
    }

    public void setA(A a) {
    
    
        this.a = a;
    }

    private C c;

    public C getC() {
    
    
        return c;
    }

    public void setC(C c) {
    
    
        this.c = c;
    }
}

C

package com4;

public class C {
    
    
    private A a;

    public A getA() {
    
    
        return a;
    }

    public void setA(A a) {
    
    
        this.a = a;
    }
}

容器类

仿照spring框架源码编写如下java代码

package com4;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;


public class Container {
    
    

    Map<String, Class> beanMap = new HashMap<>(16);


    public void addBean(String name, Class clazz){
    
    
        beanMap.put(name, clazz);
    }


    Map<String, Object> singletonObjects = new HashMap<>(16);


    Map<String, Object> earlySingletonObjects = new HashMap<>(16);


    Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);


    private void addSingleton(String beanName, Object singletonObject) {
    
    
        synchronized (this.singletonObjects) {
    
    
            this.singletonObjects.put(beanName, singletonObject);
            this.singletonFactories.remove(beanName);
            this.earlySingletonObjects.remove(beanName);
        }
    }

    private Object getSingleton(String beanName) throws Exception{
    
    
        // 一级别缓存找
        Object singletonObject = this.singletonObjects.get(beanName);
        if (singletonObject == null) {
    
    
            synchronized (this.singletonObjects) {
    
    
                // 二级别缓存找
                singletonObject = this.earlySingletonObjects.get(beanName);
                if (singletonObject == null) {
    
    
                    // 三级别缓存找
                    ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                    if (singletonFactory != null) {
    
    
                        // lambda执行后 塞到二级缓存中,并清空三级缓存
                        singletonObject = singletonFactory.getObject();
                        this.earlySingletonObjects.put(beanName, singletonObject);
                        this.singletonFactories.remove(beanName);
                        System.out.println("from singletonFactory to earlySingletonObjects bean:" + beanName);
                    }
                } else {
    
     // 多加一个else 理解 earlySingletonObjects 和 singletonFactories
                    System.out.println("just get from earlySingletonObjects:" + beanName);
                }
            }
        }
        return singletonObject;
    }

    private Object getEarlyBeanReference(String name, Object o){
    
    
        // 执行lambda,应用后处理 // TODO
        System.out.println("execute lambda to get:" + name);
        return o;
    }

    // 真正创建bean
    public Object doCreateBean(String name) throws Exception{
    
    
        System.out.println("crate bean: " + name);
        if (this.singletonObjects.containsKey(name)) {
    
    
            return this.singletonObjects.get(name);
        }
        // 初始化实例
        Class clazz = beanMap.get(name);
        Constructor constructor = clazz.getConstructors()[0];
        constructor.setAccessible(true);
        Object o = constructor.newInstance();

        // 加入三级缓存中
        System.out.println("add to singletonFactories bean:" + name);
        singletonFactories.put(name, () -> getEarlyBeanReference(name, o));

        Object exposedObj = o;
        // 设置属性, 有循环依赖,假设field的set方法都是依赖哈
        Field[] fields =  exposedObj.getClass().getDeclaredFields();
        for (Field field : fields) {
    
    
            String name2 = field.getName();
            String beanName2 = name2.toUpperCase();
            Class clazz2 = field.getType();
            System.out.println("resolve dependency bean: " + beanName2);
            Object o2 = getSingleton(beanName2);
            if (o2 == null) {
    
    
                o2 = doCreateBean(beanName2);
            }
            String beanSetMethodName = "set" + beanName2;
            Method method = clazz.getDeclaredMethod(beanSetMethodName, clazz2);
            method.invoke(exposedObj, o2);
            System.out.println(String.format("bean:%s set dependency bean:%s success", name, name2));
        }

        // 加入以及缓存并清空二级,三级缓存
        System.out.println("addSingleton bean: " + name);
        addSingleton(name, exposedObj);

        return exposedObj;
    }

    public static void main(String[] args) throws Exception {
    
    
        Container container = new Container();
        container.addBean("A", A.class);
        container.addBean("B", B.class);
        container.addBean("C", C.class);
        A a = (A) container.doCreateBean("A");
        B b = (B) container.doCreateBean("B");
        C c = (C) container.doCreateBean("C");

        System.out.println("------------------------------");
        System.out.println(a + ":  " + a.getB());
        System.out.println(b + ":  " + b.getA() + ": " + b.getC());
        System.out.println(c + ":  " + c.getA());
    }

测试输入如下

crate bean: A // 创建A
add to singletonFactories bean:A // 加入到三级缓存
resolve dependency bean: B
crate bean: B // 发现依赖B, 创建B
add to singletonFactories bean:B
resolve dependency bean: A // B依赖A
execute lambda to get:A // 三级缓存有A,执行并塞到二级缓存
from singletonFactory to earlySingletonObjects bean:A
bean:B set dependency bean:a success
resolve dependency bean: C
crate bean: C // B 依赖 C, 创建C
add to singletonFactories bean:C
resolve dependency bean: A 
just get from earlySingletonObjects:A // C 依赖 A, 直接从二级缓存取
bean:C set dependency bean:a success
addSingleton bean: C // C创建完成
bean:B set dependency bean:c success
addSingleton bean: B // B创建完成
bean:A set dependency bean:b success
addSingleton bean: A // A创建完成
crate bean: B // 获取B从一级缓存直接取
crate bean: C // 获取C从一级缓存直接取
------------------------------
com4.A@3d075dc0:  com4.B@214c265e
com4.B@214c265e:  com4.A@3d075dc0: com4.C@448139f0
com4.C@448139f0:  com4.A@3d075dc0

可以看到A,B,C 都成功创建, 且依赖关系也正确

总结

关于理解为什么需要三级缓存以及三级缓存的作用,通过本文实际例子是可以充分说明的。

实际上看:只有A,B的相互依赖,二级缓存就够了;只需要存储一个中间对象:A 创建依赖B, B创建依赖A,从这个中间缓存取就能完成创建B, 那么A也创建完成了,这样之后A,B都加入到一级缓存singletonObjects中,很完美。

但是考虑到上述A,B, C就可以多一个缓存了,考虑输出的注释

just get from earlySingletonObjects:A // C 依赖 A, 直接从二级缓存取

B、C都依赖A, B从中间缓存得到lambda且执行后可以再次进行缓存,这样C直接从这个缓存取出来用;依此类推,如果D、E、F…都依赖A,也是直接取出来,这样省了lambda的执行,所以二级缓存减少了这个开销,而三级缓存lambda则是必备,用来延迟加载获取依赖bean,拥有此缓存才能完成相互依赖的设置。

lambda延迟加载可以简单阅读我的博文:Java Function & Supplier 的实际例子对比感受抽象和懒加载


最后请读者仔细阅读代码直接拷贝然后去运行、多看看、已加深理解。如果有不一样的想法欢迎评论此博文进行交流。

猜你喜欢

转载自blog.csdn.net/qq_26437925/article/details/132250226