• Spring之为什么要用三级缓存


      刚才看了手机上的公众号,看到一个问题,Spring为什么会有三级缓存,只用两级缓存行不行

      结论当然是不行,毕竟做Spring的又不是傻蛋,大师考虑问题那可是很深远的

      在AbstractAutowireCapableBeanFactory # doCreateBean 方法中,实例化一个bean之后,填充属性值之前,会把该bean放到三级缓存中

    addSingletonFactory(beanName, new ObjectFactory<Object>() {
                    @Override
                    public Object getObject() throws BeansException {
                        return getEarlyBeanReference(beanName, mbd, bean);
                    }
                });

      AbstractAutowireCapableBeanFactory # getEarlyBeanReference

      getEarlyBeanReference既是AbstractAutowireCapableBeanFactory 这个BeanFactory的方法名也是

      SmartInstantiationAwareBeanPostProcessor这个beanPostProcessor的方法名

    protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
            Object exposedObject = bean;
            if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
                for (BeanPostProcessor bp : getBeanPostProcessors()) {
                    if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
                        SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
                        exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
                    }
                }
            }
            return exposedObject;
        }

      beanFactory中就是调用每个beanPostProcessor的getEarlyBeanReference

    这段代码是中getEarlyBeanReference方法作用是AOP

           AbstractAutoProxyCreator就实现了这个方法

    protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
            Object exposedObject = bean;
            if (bean != null && !mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
                for (BeanPostProcessor bp : getBeanPostProcessors()) {
                    if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
                        SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
                        exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
                        if (exposedObject == null) {
                            return null;
                        }
                    }
                }
            }
            return exposedObject;
        }

      这里对于一个bean如果应该动态代理就创建代理,如果是普通对象就直接返回普通对象

      如果此时有循环依赖,进一步假设这个bean是应该进行动态代理的,那么在B获取A的时候,就会调用这个  getEarlyBeanReference ,并且清除三级缓存,并放入二级缓存

      我们再往下看,看  AbstractAutowireCapableBeanFactory.doCreateBean 中的568行

    if (earlySingletonExposure) {
                Object earlySingletonReference = getSingleton(beanName, false);
                if (earlySingletonReference != null) {//如果从一级缓存或二级缓存里取得出来的话,把缓存中的bean返回,保证是同一个对象
                    if (exposedObject == bean) {
                        exposedObject = earlySingletonReference;
                    }

      注意那个false入参

    protected Object getSingleton(String beanName, boolean allowEarlyReference) {
            Object singletonObject = this.singletonObjects.get(beanName);
            if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
                synchronized (this.singletonObjects) {
                    singletonObject = this.earlySingletonObjects.get(beanName);//由于入参是false,下面的逻辑不会走,只会在二级缓存里取
                    if (singletonObject == null && allowEarlyReference) {
                        ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                        if (singletonFactory != null) {
                            singletonObject = singletonFactory.getObject();
                            this.earlySingletonObjects.put(beanName, singletonObject);
                            this.singletonFactories.remove(beanName);
                        }
                    }
                }
            }
            return (singletonObject != NULL_OBJECT ? singletonObject : null);
        }

      =============2021-09-02=============

      AbstractAutowireCapableBeanFactory 

        // Initialize the bean instance.
            Object exposedObject = bean;
            try {
                populateBean(beanName, mbd, instanceWrapper);//填充属性,会发生循环依赖 @1
                exposedObject = initializeBean(beanName, exposedObject, mbd);//这里有后置处理器beanPostProcessor,可能会进行aop @2
            }
            catch (Throwable ex) {
                if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
                    throw (BeanCreationException) ex;
                }
                else {
                    throw new BeanCreationException(
                            mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
                }
            }
    
            if (earlySingletonExposure) {
                Object earlySingletonReference = getSingleton(beanName, false);
                if (earlySingletonReference != null) {
                    if (exposedObject == bean) {//相等
                        exposedObject = earlySingletonReference;
                    }

      再来理一下思路,假设当前正在创建beanA,beanA依赖beanB,beanB也依赖beanA。

      当在实例化BeanA之后,会接着执行populateBean会填充beanB。结果beanB发现自己也需要依赖beanA,此时就会触发三级缓存中的ObjectFactory方法。如果beanA刚好要进行aop,那么在beanB的实例化过程中,由于beanB依赖了beanA,beanA就会提前进行aop,然后将beanA从三级缓存中清掉,再将beanA放入二级缓存。

      在@2处,进行aop之前会判断该beanName是否已经进行过aop,所以这个beanA不会再次被增强。

       Object earlySingletonReference = getSingleton(beanName, false); 第二个参数是false,只会从一级和二级缓存中取。如果beanA被beanB循环依赖,且经过aop,那么beanA肯定在二级缓存。所以 earlySingletonReference != null 为true。

      由于在循环依赖中已经经过了aop,所以 exposedObject == bean 为true

      所以对 exposedObject 赋值,保证最终拿到的bean是经过了aop的beanA。

      

      如果真的有循环依赖,那么这个bean一定会从三级缓存进入二级缓存,如果这个bean刚好是要被AOP的,那么就一定要保证bean的单例性。所以在最终返回bean之前,检查二级缓存里有没有该对象,如果有就一定要用缓存里的对象。如果没有循环依赖,那么这个bean肯定在三级缓存里呆着呢,这里由于入参是false。也不会去三级缓存里拿。

    Object earlySingletonReference = getSingleton(beanName, false);

      那么这里earlySingletonReference 就是 null,beanA的值就是开始进行实例化的beanA。

    结论

      只有两级缓存行不行呢?没有aop是可以的,有aop的话就不行了。

      

  • 相关阅读:
    SQL Server创建复合索引时,复合索引列顺序对查询的性能影响
    SQL 查询性能优化----解决书签查找
    从源码分析 Spring 基于注解的事务
    jQuery最佳实践(不断更新中...)
    Java 8 LongAdders:管理并发计数器的正确方式
    Java中的显示锁 ReentrantLock 和 ReentrantReadWriteLock
    在IE8等不支持placeholder属性的浏览器中模拟placeholder效果
    颠覆式前端UI开发框架:React
    Whitecoin区块链钱包高级功能使用命令
    消息队列使用的四种场景介绍
  • 原文地址:https://www.cnblogs.com/juniorMa/p/14087517.html
Copyright © 2020-2023  润新知