Pratique des dépendances circulaires Spring et compréhension du cache de troisième niveau

Organigramme des dépendances circulaires Spring

J'ai lu le code source et écrit un résumé il y a longtemps :
https://github.com/doctording/spring-framework-5.1.3.RELEASE/blob/dev/docs/doc/bean/dependency.md

Le processus de création de l’interdépendance A et B est illustré dans la figure suivante :
insérer la description de l'image ici

Scénario : A dépend de B ; B dépend de A et C ; C dépend de A

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

Définition de trois classes A, B, C

UN

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;
    }
}

classe de conteneur

Suivez le code source du framework Spring pour écrire le code Java suivant

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());
    }

L'entrée du test est la suivante

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

Vous pouvez voir que A, B et C ont tous été créés avec succès et que les dépendances sont également correctes.

Résumer

Concernant la compréhension de la raison pour laquelle le cache de troisième niveau est nécessaire et du rôle du cache de troisième niveau, cela peut être pleinement expliqué à travers les exemples réels de cet article.

En fait, seuls A et B dépendent l'un de l'autre, et le cache de deuxième niveau suffit ; un seul objet intermédiaire doit être stocké : A crée une dépendance sur B, B crée une dépendance sur A, et la création de B peut être complété en récupérant à partir de ce cache intermédiaire, alors A doit également être stocké. Une fois la création terminée, A et B sont ajoutés au cache singletonObjects de premier niveau, ce qui est parfait.

Mais compte tenu des points A, B, C ci-dessus, vous pouvez avoir un cache supplémentaire, considérez les commentaires de sortie

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

B et C dépendent tous deux de A, et B récupère le lambda du cache intermédiaire et peut le remettre en cache après l'exécution, afin que C puisse être utilisé directement à partir de ce cache ; et ainsi de suite, si D, E, F... tous dépendent de A, ils peuvent également être directement retirés , ce qui enregistre l'exécution de lambda, donc le cache de deuxième niveau réduit cette surcharge , et le cache lambda de troisième niveau est nécessaire pour retarder le chargement et obtenir les beans dépendants. Uniquement avec ce cache les réglages interdépendants peuvent-ils être complétés.

Le chargement paresseux de lambda peut simplement lire mon article de blog : L'exemple réel de Java Function & Supplier compare l'abstraction et le chargement paresseux


Enfin, veuillez lire attentivement le code et copier-le directement, puis exécutez-le, lisez-en davantage et approfondissez votre compréhension. Si vous avez des idées différentes, veuillez commenter cet article de blog pour communiquer.

Je suppose que tu aimes

Origine blog.csdn.net/qq_26437925/article/details/132250226
conseillé
Classement