spring的三级缓存

Spring的三级缓存解决循环依赖问题
为了更好的理解循环依赖的问题,我们先一点一点手写循环依赖的代码
模拟spring的getBean简易流程,首先是只有一级缓存,

public class Criculation {
    //一级缓存
    private static HashMap<String, Object> singletonMap = new HashMap<String, Object> ();
    //bean定义的Map
    private static HashMap<String, RootBeanDefinition> beanDefinitionMap = new HashMap<> ();

    public static void main(String[] args) throws Exception {
// InstanceA和InstanceB两个beanDefinition
        RootBeanDefinition beanDefinitionA = new RootBeanDefinition (InstanceA.class);
        RootBeanDefinition beanDefinitionB = new RootBeanDefinition (InstanceB.class);
//beanDefinitionMap存放beanDefinition
        beanDefinitionMap.put ("instanceA", beanDefinitionA);
        beanDefinitionMap.put ("instanceB", beanDefinitionB);
        Object instanceA = getBean ("instanceA");
//        ((InstanceA)instanceA).hello ();
        ((InstanceB)singletonMap.get("instanceB")).getInstanceA ().hello ();
    }
//getBean方法获取bean
    public static Object getBean(String beanName) throws Exception {
//首先向一级缓存获取bean,如果获取到直接返回
        Object bean = singletonMap.get (beanName);
        if (bean != null) {
            return bean;
        }
//从beanDefinitionMap中获取对应的beanDefinition
        RootBeanDefinition rootBeanDefinition = beanDefinitionMap.get (beanName);
//因为是模拟,直接使用了无参构造器获取bean实例,此时bean属性没有赋值
        Class<?> beanClass = rootBeanDefinition.getBeanClass ();
        Object instanceBean = beanClass.newInstance ();
        Field[] declaredFields = beanClass.getDeclaredFields ();
        //这样解决循环依赖,最终得到的InstanceA的成员变量instanceB指向InstanceB而    
//InstanceB的成员变量instanceA指向InstanceA形成了环
//为什么解决了循环依赖,就是InstanceB再依赖InstanceA之前先从一级缓存中获取,此时的InstanceA只实例化,没有属性赋值,就是下面这个代码,在没有赋值之前就将InstanceA放到一级缓存中
        singletonMap.put (beanName, instanceBean);
//遍历属性
        Arrays.stream (declaredFields).forEach (o -> {
        //如果属性标注了Autowired注解,则getBean获取实例    
Annotation annotation = o.getAnnotation (Autowired.class);
            if (annotation != null) {
                try {
                    Object beanField = getBean (o.getName ());
//有可能是private
                    o.setAccessible (true);
//为属性赋值
                    o.set (instanceBean, beanField);
                } catch (Exception e) {
                    e.printStackTrace ();
                }
            }

        });
//把bean放到一级缓存中,这段代码上面也有,如果放在上面可以解决循环依赖,如果不能理解,可以用debug的模式跟代码 就能明白
//如果放在这的话,抛出栈溢出的异常
       singletonMap.put (beanName, instanceBean);
        return instanceBean;
    }
}
//两个循环依赖的类
@Data
class InstanceA {
    @Autowired
    private InstanceB instanceB;
    public  void hello(){
        System.out.println ("hello");
    }
}
@Data
class InstanceB {
    @Autowired
    private InstanceA instanceA;
}

两个类的关系如下图,红色部分为toString方法的异常,因为toString是要打印类实例化的信息,包含所有的成员变量,因为变量是相互的指向,所以调用toSting的时候,出现栈溢出错误,


image.png

只有一级缓存有能力解决循环依赖,但是出现了不完整Bean的真空期(实例化后先放到容器中再赋值),如果是多线程的话,在一级缓存中可能获取到的bean是不完整的,可以考虑将不完整的bean放到二级缓存中.

public class Criculation {
    //一级缓存
    private static HashMap<String, Object> singletonMap = new HashMap<String, Object> ();
    //二级缓存
    private static HashMap<String, Object> earlySingletonMap = new HashMap<String, Object> ();
    //bean定义的Map
    private static HashMap<String, RootBeanDefinition> beanDefinitionMap = new HashMap<> ();

    public static void main(String[] args) throws Exception {
        RootBeanDefinition beanDefinitionA = new RootBeanDefinition (InstanceA.class);
        RootBeanDefinition beanDefinitionB = new RootBeanDefinition (InstanceB.class);
        beanDefinitionMap.put ("instanceA", beanDefinitionA);
        beanDefinitionMap.put ("instanceB", beanDefinitionB);
        Object instanceA = getBean ("instanceA");
        ((InstanceA)instanceA).hello ();
    }
    public static Object getBean(String beanName) throws Exception {
        //一级缓存中获取完整bean
        if (singletonMap.containsKey (beanName)) {
            return singletonMap.get (beanName);
            //二级缓存中获取的bean为不完成的bean,解决循环依赖
        } else if (earlySingletonMap.containsKey (beanName)) {
            return earlySingletonMap.get (beanName);
        }
        RootBeanDefinition rootBeanDefinition = beanDefinitionMap.get (beanName);
        Class<?> beanClass = rootBeanDefinition.getBeanClass ();
        Object instanceBean = beanClass.newInstance ();
        Field[] declaredFields = beanClass.getDeclaredFields ();
        //将实例化但是没有属性赋值bean放到二级缓存中
        earlySingletonMap.put (beanName, instanceBean);
        Arrays.stream (declaredFields).forEach (o -> {
            Annotation annotation = o.getAnnotation (Autowired.class);
            if (annotation != null) {
                try {
                    Object beanField = getBean (o.getName ());
                    o.setAccessible (true);
                    o.set (instanceBean, beanField);
                } catch (Exception e) {
                    e.printStackTrace ();
                }
            }
        });
        //将完整的bean放到一级缓存中
        singletonMap.put (beanName, instanceBean);
        return instanceBean;
    }
}
@Data
class InstanceA {
    @Autowired
    private InstanceB instanceB;
    public void hello() {
        System.out.println ("hello");
    }
}
@Data
class InstanceB {
    @Autowired
    private InstanceA instanceA;
}

当然得到的结果和上面的图片是一样的.

下面是三级缓存,高度还原了spring的源码,源码中实例化和属性赋值都是通过bean的后置处理器实现的,为了解耦,本实例采用的是无参构造器反射实例化,赋值直接为@Autowired属性赋值,

DefaultBeanFactory类

public class DefaultBeanFactory extends SingletonBeanRegistry {
//存放bean定义
    private final Map<String, RootBeanDefinition> beanDefinitionMap = new ConcurrentHashMap<> ();

    public void registerBeanDefinition(String beanName, RootBeanDefinition beanDefinition) {
        this.beanDefinitionMap.put (beanName, beanDefinition);
    }


    public Object getBean(String name) throws Exception {
        return doGetBean (name);
    }

    private <T> T doGetBean(String beanName) throws Exception {
        Object bean;
        //获取bean
        Object sharedInstance = getSingleton (beanName, true);
        if (sharedInstance != null) {
            bean = sharedInstance;
        } else {
//一级缓存没有bean,创建bean,首先获取bean定义
            RootBeanDefinition beanDefinition = this.beanDefinitionMap.get (beanName);
            if (beanDefinition == null) {
                throw new AssociationException ("can not find the definition of bean '" + beanName + "'");
            }
            //创建bean并属性赋值
            bean = getSingleton (beanName, () -> {
                try {
                    return doCreateBean (beanName, beanDefinition);
                } catch (BeansException ex) {
                    removeSingleton (beanName);
                    throw ex;
                }
            });
        }
        return ( T ) bean;
    }

    private Object doCreateBean(String beanName, RootBeanDefinition beanDefinition) throws BeansException {
        //创建实例,这里只是用了无参构造器
        Object bean = createBeanInstance (beanName, beanDefinition);
        boolean earlySingletonExposure = isSingletonCurrentlyInCreation (beanName);
        if (earlySingletonExposure) {
            addSingletonFactory (beanName, () -> bean);
        }
        Object exposedObject = bean;
        //属性赋值
        populateBean (beanName, beanDefinition, bean);
        if (earlySingletonExposure) {
            Object earlySingletonReference = getSingleton (beanName, false);
            if (earlySingletonReference != null) {
                exposedObject = earlySingletonReference;
            }
        }
        return exposedObject;
    }
/**    createBeanInstance方法在源码中的实现方式
 * AbstractAutowireCapableBeanFactory#createBeanInstance
    Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);获取构造函数
    autowireConstructor(beanName, mbd, ctors, null);通过有参构造创建bean实例(未初始化)
    instantiateBean(beanName, mbd);通过无参构造创建bean(未初始换)*/
    private Object createBeanInstance(String beanName, RootBeanDefinition beanDefinition) throws BeansException {
        Class<?> beanClass = beanDefinition.getBeanClass ();
        Constructor<?> constructorToUse;
        if (beanClass.isInterface ()) {
            throw new BeanCreationException ("Specified class '" + beanName + "' is an interface");
        }
        try {
            constructorToUse = beanClass.getDeclaredConstructor (( Class<?>[] ) null);
            constructorToUse.setAccessible (true);
            return constructorToUse.newInstance ();
        } catch (Exception e) {
            throw new BeanCreationException ("'" + beanName + "',No default constructor found", e);
        }
    }

    /**
     * 源码中populateBean方法是通过下面两个bean后置处理器为属性赋值
     AutowiredAnnotationBeanPostProcessor#postProcessProperties 为@Autowired和@Value赋值
     CommonAnnotationBeanPostProcessor#postProcessProperties    为@Resource赋值
     */
    private void populateBean(String beanName, RootBeanDefinition beanDefinition, Object beanInstance)  {
        Field[] beanFields = beanDefinition.getBeanClass ().getDeclaredFields ();
        Arrays.stream (beanFields).forEach (o -> {
            Annotation annotation = o.getAnnotation (Autowired.class);
            if (annotation != null) {
                try {
                    Object beanField = getBean (o.getName ());
                    o.setAccessible (true);
                    o.set (beanInstance, beanField);
                } catch (Exception e) {
                    e.printStackTrace ();
                }
            }
        });
    }
}

SingletonBeanRegistry类

public class SingletonBeanRegistry {

    private static final Object NULL_OBJECT = new Object();
//一级缓存
    private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>();
//二级缓存
    private final Map<String, Object> earlySingletonObjects = new HashMap<>();
//三级缓存
    private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>();
//正在创建标识
    private final Set<String> singletonsCurrentlyInCreation = Collections.newSetFromMap(new ConcurrentHashMap<>());

    protected Object getSingleton(String beanName,boolean allowEarlyReference)  {
        //从一级缓存获取完整bean
        Object singletonObject = this.singletonObjects.get(beanName);
        //一级缓存为空,并且正在创建,出现循环依赖的情况
        if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
            synchronized (this.singletonObjects) {
                //从二级缓存中获取
                singletonObject = this.earlySingletonObjects.get(beanName);
                //二级缓存为空,allowEarlyReference为true 利用三级缓存创建bean
                if (singletonObject == null && allowEarlyReference) {
                    //从三级缓存获取
                    ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                    //如果不为空
                    if (singletonFactory != null) {
                        //调用了函数接口,其实也是直接返回bean
                        singletonObject = singletonFactory.getObject();
                        //存放进二级缓存,这里及存在了线程安全问题
                        this.earlySingletonObjects.put(beanName, singletonObject);
                        //从三级缓存中移除
                        this.singletonFactories.remove(beanName);
                    }
                }
            }
        }
        return (singletonObject != NULL_OBJECT ? singletonObject : null);
    }

    protected Object getSingleton(String beanName, ObjectFactory<?> singletonFactory)  {
        synchronized (this.singletonObjects) {
            //从一级缓存中获取
            Object singletonObject = this.singletonObjects.get(beanName);
            if (singletonObject == null) {
                //添加到正在创建集合
                this.singletonsCurrentlyInCreation.add(beanName);
                //调用doCreateBean方法
                singletonObject = singletonFactory.getObject();
                //从正在创建集合移除
                this.singletonsCurrentlyInCreation.remove(beanName);
                //添加到一级缓存,从二级三级缓存中移除
                addSingleton(beanName, singletonObject);
            }
            return (singletonObject != NULL_OBJECT ? singletonObject : null);
        }
    }

    protected void addSingleton(String beanName, Object singletonObject) {
        synchronized (this.singletonObjects) {
            this.singletonObjects.put(beanName, (singletonObject != null ? singletonObject : NULL_OBJECT));
            this.singletonFactories.remove(beanName);
            this.earlySingletonObjects.remove(beanName);
        }
    }

    protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
        synchronized (this.singletonObjects) {
            if (!this.singletonObjects.containsKey(beanName)) {
                this.singletonFactories.put(beanName, singletonFactory);
                this.earlySingletonObjects.remove(beanName);
            }
        }
    }

    protected void removeSingleton(String beanName) {
        synchronized (this.singletonObjects) {
            this.singletonObjects.remove(beanName);
            this.singletonFactories.remove(beanName);
            this.earlySingletonObjects.remove(beanName);
        }
    }

    protected boolean isSingletonCurrentlyInCreation(String beanName) {
        return this.singletonsCurrentlyInCreation.contains(beanName);
    }

}

测试代码

public class MainTest {
    public static void main(String[] args) throws Exception {
        RootBeanDefinition beanDefinitionA = new RootBeanDefinition();
        beanDefinitionA.setBeanClass (InstanceA.class);
        RootBeanDefinition beanDefinitionB = new RootBeanDefinition();
        beanDefinitionB.setBeanClass (InstanceB.class);
        DefaultBeanFactory defaultBeanFactory = new DefaultBeanFactory ();
        defaultBeanFactory.registerBeanDefinition ("instanceA",beanDefinitionA);
        defaultBeanFactory.registerBeanDefinition ("instanceB",beanDefinitionB);
        Object instanceA = defaultBeanFactory.getBean ("instanceA");
    }
}
@Data
class InstanceA {
    @Autowired
    private InstanceB instanceB;

    public InstanceA() {
        System.out.println ("InstanceA初始化");
    }
}
@Data
class InstanceB {
    @Autowired
    private InstanceA instanceA;
    public InstanceB() {
        System.out.println ("InstanceB初始化");
    }
}

第三级缓存都是存放的lambda表达式,也是解耦
代码的分析用下面的图简单的讲解一下,可以结合debuger 一点点调试

image.png

image.png

image.png

image.png

image.png

在第四张图如果此时线程2创建InstanceA的话,二级缓存中有不完整的实例,并且正在创建队列中含有InstanceA
Object sharedInstance = getSingleton (beanName, true);直接返回的就是InstanceA的不完成实例所以使用synchronized加锁,保证线程安全.
一级缓存和三级缓存不管是否是循环依赖都要使用,只要在循环依赖的情况下才会使用到二级缓存,加锁的方式防止多线程从二级缓存中获取没有初始化好的类.

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,186评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,858评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,620评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,888评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,009评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,149评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,204评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,956评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,385评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,698评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,863评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,544评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,185评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,899评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,141评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,684评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,750评论 2 351

推荐阅读更多精彩内容