剛才看了手機上的公眾號,看到一個問題,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方法作用是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,此時就會觸發三級緩存中的factory方法。如果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的話就不行了。