wifi擴(kuò)展器做網(wǎng)站百度資源平臺(tái)鏈接提交
文章目錄
- 一、目標(biāo):通過三級(jí)緩存解決循環(huán)依賴
- 二、設(shè)計(jì):通過三級(jí)緩存解決循環(huán)依賴
- 2.1 通過三級(jí)緩存解決循環(huán)依賴
- 2.2 嘗試使用一級(jí)緩存解決循環(huán)依賴
- 三、實(shí)現(xiàn):通過三級(jí)緩存解決循環(huán)依賴
- 3.1 工程結(jié)構(gòu)
- 3.2 通過三級(jí)緩存解決循環(huán)依賴類圖
- 3.3 設(shè)置三級(jí)緩存
- 3.3.1 對(duì)象工廠
- 3.3.2 設(shè)置三級(jí)緩存
- 3.4 提前暴露對(duì)象
- 3.4.1 實(shí)例化感知對(duì)象處理
- 3.4.2 默認(rèn)自動(dòng)代理創(chuàng)建者
- 3.4.3 實(shí)現(xiàn)默認(rèn)bean創(chuàng)建的抽象bean工廠超類
- 四、測試:通過三級(jí)緩存解決循環(huán)依賴
- 4.1 添加測試配置
- 4.1.1 老公類
- 4.1.2 媳婦類
- 4.1.3 婆婆接口
- 4.1.4 婆婆代理類
- 4.1.5 切面
- 4.1.6 Spring屬性配置文件
- 4.2 單元測試
- 五、總結(jié):通過三級(jí)緩存解決循環(huán)依賴
一、目標(biāo):通過三級(jí)緩存解決循環(huán)依賴
💡 如何解決類與類之間的循環(huán)依賴?
- 在目前的 Spring 框架中,如果你配置了
A、B
兩個(gè) Bean 對(duì)象互相依賴,那么立刻會(huì)拋出java.lang.StackOverflowError
,為什么?- 因?yàn)?A 創(chuàng)建時(shí)需要依賴 B 創(chuàng)建,而 B 的創(chuàng)建又依賴于 A 創(chuàng)建,就這樣死循環(huán)了。
- 循環(huán)依賴 基本可以說是 Spring 中經(jīng)典的實(shí)現(xiàn),所要解決的場景主要三種情況。
- 循環(huán)依賴主要分為三種:自身依賴于自身、互相循環(huán)依賴、多組循環(huán)依賴。
- 但無論循環(huán)依賴的數(shù)量有多少,循環(huán)依賴的本質(zhì)是一樣。
- 就是你的完整創(chuàng)建依賴于我,而我的完整創(chuàng)建也依賴于你,但我們互相沒法解耦,最終導(dǎo)致依賴創(chuàng)建失敗。
- 所以需要 Spring 提供除了構(gòu)造函數(shù)注入和原型注入外的,
setter
循環(huán)依賴注入解決方案。
二、設(shè)計(jì):通過三級(jí)緩存解決循環(huán)依賴
2.1 通過三級(jí)緩存解決循環(huán)依賴
💡 設(shè)計(jì):通過三級(jí)緩存解決循環(huán)依賴
- 用于解決循環(huán)依賴需要用到三個(gè)緩存,這三個(gè)緩存分別存放:
成品對(duì)象、半成品對(duì)象(未填充屬性值)、代理對(duì)象
,分階段存放對(duì)象內(nèi)容,來解決循環(huán)依賴問題。
- 需要知道核心原理:用于解決循環(huán)依賴就必須是三級(jí)緩存嗎?二級(jí)緩存行嗎?一級(jí)緩存行嗎?
- 其實(shí)都能解決。但是 Spring 框架的實(shí)現(xiàn)要保證幾個(gè)事情。如:
- 只有一級(jí)緩存處理流程沒法拆分,復(fù)雜度也會(huì)增加,同時(shí)半成品對(duì)象可能會(huì)有空指針異常。
- 而將半成品與成品對(duì)象分開,處理起來也更加優(yōu)雅、簡單、易擴(kuò)展。
- 另外 Spring 的兩大特性中不僅有 IOC,還有 AOP,也就是基于字節(jié)碼增強(qiáng)后的方法,該存放到哪。
- 而三級(jí)緩存最主要,要解決的循環(huán)依賴就是對(duì) AOP 的處理,但如果把 AOP 代理對(duì)象的創(chuàng)建提前,那么二級(jí)緩存也一樣可以解決。
- 但是,這就違背了 Spring 創(chuàng)建對(duì)象的原則,Spring 更喜歡把所有的普通 Bean 都初始化完成,再處理代理對(duì)象的初始化。
- 其實(shí)都能解決。但是 Spring 框架的實(shí)現(xiàn)要保證幾個(gè)事情。如:
- 思考:如果有對(duì)象不只是簡單的對(duì)象,還有代理對(duì)象,還有 AOP 應(yīng)用,要怎么處理這樣的依賴問題。
- 關(guān)于循環(huán)依賴在目前的 Spring 框架中,主要就是對(duì)于創(chuàng)建的提前暴露。
- 如果是工廠對(duì)象則會(huì)使用
getEarlyBeanReference
邏輯提前將工廠對(duì)象存放到三級(jí)緩存中。 - 等到后續(xù)獲取對(duì)象的時(shí)候?qū)嶋H拿到的是工廠對(duì)象中
getObject
,這個(gè)才是最終的實(shí)際對(duì)象。
- 如果是工廠對(duì)象則會(huì)使用
- 在創(chuàng)建對(duì)象的
AbstractAutowireCapableBeanFactory#doCreateBean
方法中,提前暴露對(duì)象以后。- 就可以通過接下來的流程,
getSingleton
從三個(gè)緩存中以此尋找對(duì)象。 - 一級(jí)、二級(jí)如果有則直接取走,如果對(duì)象是三級(jí)緩存中則會(huì)從三級(jí)緩存中獲取后并刪掉工廠對(duì)象,把實(shí)際對(duì)象放到二級(jí)緩存中。
- 就可以通過接下來的流程,
- 最后是關(guān)于單例的對(duì)象的注冊(cè)操作,這個(gè)注冊(cè)操作就是把真實(shí)的實(shí)際對(duì)象放到一級(jí)緩存中,因?yàn)榇藭r(shí)它已經(jīng)是一個(gè)成品對(duì)象了。
2.2 嘗試使用一級(jí)緩存解決循環(huán)依賴
- 如果僅以一級(jí)緩存解決循環(huán)依賴,那么在實(shí)現(xiàn)上可以通過 A 對(duì)象
newInstance
創(chuàng)建且未填充屬性后,直接放入緩存中。 - 在 A 對(duì)象的屬性填充 B 對(duì)象時(shí),如果緩存中不能獲取到 B 對(duì)象,則開始創(chuàng)建 B 對(duì)象,同樣創(chuàng)建完成后,把 B 對(duì)象填充到緩存中。
- 接下來就開始對(duì) B 對(duì)象的屬性進(jìn)行填充,恰好這會(huì)可以從緩存中拿到半成品的 A 對(duì)象,那么這個(gè)時(shí)候 B 對(duì)象的屬性就填充完了。
- 最后返回來繼續(xù)完成 A 對(duì)象的屬性填充,把實(shí)例化后并填充了屬性的 B 對(duì)象賦值給 A 對(duì)象的
b
屬性,這樣就完成了一個(gè)循環(huán)依賴操作。
CircleTest.java
package com.lino.springframework.test;import java.lang.reflect.Field;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;/*** @description: 循環(huán)依賴案例*/
public class CircleTest {private final static Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);public static void main(String[] args) throws Exception {System.out.println(getBean(B.class).getA());System.out.println(getBean(A.class).getB());}private static <T> T getBean(Class<T> beanClass) throws Exception {String beanName = beanClass.getSimpleName().toLowerCase();if (singletonObjects.containsKey(beanName)) {return (T) singletonObjects.get(beanName);}// 實(shí)例化對(duì)象入緩存Object obj = beanClass.newInstance();singletonObjects.put(beanName, obj);// 屬性填充補(bǔ)全對(duì)象Field[] fields = obj.getClass().getDeclaredFields();for (Field field : fields) {field.setAccessible(true);Class<?> fieldClass = field.getType();String fieldBeanName = fieldClass.getSimpleName().toLowerCase();field.set(obj, singletonObjects.containsKey(fieldBeanName) ? singletonObjects.get(fieldBeanName) : getBean(fieldClass));field.setAccessible(false);}return (T) obj;}
}class A {private B b;public B getB() {return b;}public void setB(B b) {this.b = b;}
}class B {private A a;public A getA() {return a;}public void setA(A a) {this.a = a;}
}
測試結(jié)果
com.lino.springframework.test.A@266474c2
com.lino.springframework.test.B@6f94fa3e
- 從測試效果和截圖依賴過程中可以看到,一級(jí)緩存也可以解決簡單場景的循環(huán)依賴問題。
- 其實(shí)
getBean
,是整個(gè)解決循環(huán)依賴的核心內(nèi)容,A 創(chuàng)建后填充屬性時(shí)依賴 B,那么就去創(chuàng)建 B,在創(chuàng)建 B 開始填充時(shí)發(fā)現(xiàn)依賴于 A,但此時(shí) A 這個(gè)半成品對(duì)象已經(jīng)存放在緩存到singletonObjects
中了,所以 B 可以正常創(chuàng)建,再通過遞歸把 A 也創(chuàng)建完整了。
三、實(shí)現(xiàn):通過三級(jí)緩存解決循環(huán)依賴
3.1 工程結(jié)構(gòu)
spring-step-16
|-src|-main| |-java| |-com.lino.springframework| |-aop| | |-aspectj| | | |-AspectJExpressionPointcut.java| | | |-AspectJExpressionPointcutAdvisor.java| | |-framework| | | |-adapter| | | | |-MethodBeforeAdviceInterceptor.java| | | |-autoproxy| | | | |-DefaultAdvisorAutoProxyCreator.java| | | |-AopProxy.java| | | |-Cglib2AopProxy.java| | | |-JdkDynamicAopProxy.java| | | |-ProxyFactory.java| | | |-ReflectiveMethodInvocation.java| | |-AdvisedSupport.java| | |-Advisor.java| | |-BeforeAdvice.java| | |-ClassFilter.java| | |-MethodBeforeAdvice.java| | |-MethodMatcher.java| | |-Pointcut.java| | |-PointcutAdvisor.java| | |-TargetSource.java| |-beans| | |-factory| | | |-annotation| | | | |-Autowired.java| | | | |-AutowiredAnnotationBeanPostProcessor.java| | | | |-Qualifier.java| | | | |-Value.java| | | |-config| | | | |-AutowireCapableBeanFactory.java| | | | |-BeanDefinition.java| | | | |-BeanFactoryPostProcessor.java| | | | |-BeanPostProcessor.java| | | | |-BeanReference.java| | | | |-ConfigurableBeanFactory.java| | | | |-InstantiationAwareBeanPostProcessor.java| | | | |-SingletonBeanRegistry.java| | | |-support| | | | |-AbstractAutowireCapableBeanFactory.java| | | | |-AbstractBeabDefinitionReader.java| | | | |-AbstractBeabFactory.java| | | | |-BeabDefinitionReader.java| | | | |-BeanDefinitionRegistry.java| | | | |-CglibSubclassingInstantiationStrategy.java| | | | |-DefaultListableBeanFactory.java| | | | |-DefaultSingletonBeanRegistry.java| | | | |-DisposableBeanAdapter.java| | | | |-FactoryBeanRegistrySupport.java| | | | |-InstantiationStrategy.java| | | | |-SimpleInstantiationStrategy.java| | | |-xml| | | | |-XmlBeanDefinitionReader.java| | | |-Aware.java| | | |-BeanClassLoaderAware.java| | | |-BeanFactory.java| | | |-BeanFactoryAware.java| | | |-BeanNameAware.java| | | |-ConfigurableListableBeanFactory.java| | | |-DisposableBean.java| | | |-FactoryBean.java| | | |-HierarcgicalBeanFactory.java| | | |-InitializingBean.java| | | |-ListableBeanFactory.java| | | |-ObjectFactory.java| | | |-PropertyPlaceholderConfigurer.java| | |-BeansException.java| | |-PropertyValue.java| | |-PropertyValues.java| |-context| | |-annotation| | | |-ClassPathBeanDefinitionScanner.java| | | |-ClassPathScanningCandidateComponentProvider.java| | | |-Scope.java| | |-event| | | |-AbstractApplicationEventMulticaster.java| | | |-ApplicationContextEvent.java| | | |-ApplicationEventMulticaster.java| | | |-ContextclosedEvent.java| | | |-ContextRefreshedEvent.java| | | |-SimpleApplicationEventMulticaster.java| | |-support| | | |-AbstractApplicationContext.java| | | |-AbstractRefreshableApplicationContext.java| | | |-AbstractXmlApplicationContext.java| | | |-ApplicationContextAwareProcessor.java| | | |-ClassPathXmlApplicationContext.java| | |-ApplicationContext.java| | |-ApplicationContextAware.java| | |-ApplicationEvent.java| | |-ApplicationEventPublisher.java| | |-ApplicationListener.java| | |-ConfigurableApplicationContext.java| |-core.io| | |-ClassPathResource.java| | |-DefaultResourceLoader.java| | |-FileSystemResource.java| | |-Resource.java| | |-ResourceLoader.java| | |-UrlResource.java| |-stereotype| | |-Component.java| |-util| | |-ClassUtils.java| | |-StringValueResolver.java|-test|-java|-com.lino.springframework.test|-bean| |-Husband.java| |-HusbandMother.java| |-IMother.java| |-SpouseAdvice.java| |-Wife.java|-ApiTest.java|-CircleTest.java|-resources|-spring.xml
3.2 通過三級(jí)緩存解決循環(huán)依賴類圖
- 循環(huán)依賴的黑犀牛功能實(shí)現(xiàn)主要包括
DefaultSingletonBeanRegistry
提供三級(jí)緩存。singletonObjects
、earlySingletonObjects
、singletonFactiries
,分別存放成品對(duì)象、半成品對(duì)象和工廠對(duì)象。- 同時(shí)包裝三個(gè)緩存提供方法:
getSingleton
、registerSingleton
、addSingletonFactory
,這樣使用方就可以分別在不同時(shí)間段存放和獲取對(duì)應(yīng)的對(duì)象。
- 在
AbstractAutowireCapableBeanFactory
的doCreateBean
方法中,提供了關(guān)于提前暴露對(duì)象的操作。addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, beanDefinition, finalBean))
- 以及后續(xù)獲取對(duì)象和注冊(cè)對(duì)象的操作:
exposedObject = getSingleton(beanName)
、registerSingleton(beanName, exposedObject)
。 - 經(jīng)過這樣的處理就可以完成對(duì)復(fù)雜場景循環(huán)依賴的操作。
- 另外在
DefaultAdvisorAutoProxyCreator
提供的切面服務(wù)中,也需要實(shí)現(xiàn)接口InstantiationAwareBeanPostProcessor
新增的getEarlyBeanReference
方法,便于把依賴的切面對(duì)象也能存放到三級(jí)緩存中,處理對(duì)應(yīng)的循環(huán)依賴。
3.3 設(shè)置三級(jí)緩存
3.3.1 對(duì)象工廠
ObjectFactory.java
package com.lino.springframework.beans.factory;import com.lino.springframework.beans.BeansException;/*** @description: 對(duì)象工廠*/
public interface ObjectFactory<T> {/*** 獲取對(duì)象** @return 泛型對(duì)象* @throws BeansException 異常*/T getObject() throws BeansException;
}
3.3.2 設(shè)置三級(jí)緩存
DefaultSingletonBeanRegistry.java
package com.lino.springframework.beans.factory.support;import com.lino.springframework.beans.BeansException;
import com.lino.springframework.beans.factory.DisposableBean;
import com.lino.springframework.beans.factory.ObjectFactory;
import com.lino.springframework.beans.factory.config.SingletonBeanRegistry;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;/*** @description: 通用的注冊(cè)表實(shí)現(xiàn)*/
public class DefaultSingletonBeanRegistry implements SingletonBeanRegistry {protected static final Object NULL_OBJECT = new Object();/*** 一級(jí)緩存,普通對(duì)象*/private Map<String, Object> singletonObjects = new ConcurrentHashMap<>();/*** 二級(jí)緩存,提前暴露對(duì)象,沒有完全實(shí)例化的對(duì)象*/protected final Map<String, Object> earlySingletonObjects = new HashMap<>();/*** 三級(jí)緩存,存放代理對(duì)象*/private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>();private final Map<String, DisposableBean> disposableBeans = new HashMap<>();@Overridepublic Object getSingleton(String beanName) {Object singletonObject = singletonObjects.get(beanName);if (null == singletonObject) {singletonObject = earlySingletonObjects.get(beanName);// 判斷二級(jí)緩存中是否有對(duì)象,這個(gè)對(duì)象就是代理對(duì)象,因?yàn)橹挥写韺?duì)象才會(huì)放到三級(jí)緩存中if (null == singletonObject) {ObjectFactory<?> singletonFactory = singletonFactories.get(beanName);if (singletonFactory != null) {singletonObject = singletonFactory.getObject();// 把三級(jí)緩存中的代理對(duì)象中的真實(shí)對(duì)象獲取出來,放入二級(jí)緩存中earlySingletonObjects.put(beanName, singletonObject);singletonFactories.remove(beanName);}}}return singletonObject;}@Overridepublic void registerSingletonBean(String beanName, Object singletonObject) {singletonObjects.put(beanName, singletonObject);earlySingletonObjects.remove(beanName);singletonFactories.remove(beanName);}protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {if (!this.singletonObjects.containsKey(beanName)) {this.singletonFactories.put(beanName, singletonFactory);this.earlySingletonObjects.remove(beanName);}}public void registerDisposableBean(String beanName, DisposableBean bean) {disposableBeans.put(beanName, bean);}public void destroySingletons() {Set<String> keySet = this.disposableBeans.keySet();Object[] disposableBeanNames = keySet.toArray();for (int i = disposableBeanNames.length - 1; i >= 0; i--) {Object beanName = disposableBeanNames[i];DisposableBean disposableBean = disposableBeans.remove(beanName);try {disposableBean.destroy();} catch (Exception e) {throw new BeansException("Destroy method on bean with name '" + beanName + "' threw an exception", e);}}}
}
- 在用于提供單例對(duì)象注冊(cè)操作的
DefaultSingletonBeanRegistry
類中,共有三個(gè)緩存對(duì)象的屬性:singletonObjects
、earlySingletonObjects
、singletonFactories
。- 用于存放不同類型的對(duì)象:單例對(duì)象、早期的半成品單例對(duì)象、單例工廠對(duì)象。
- 緊接著在這三個(gè)緩存對(duì)象下提供了獲取、添加和注冊(cè)不同對(duì)象的方法,包括:
getSingleton
、registerSingletonBean
、addSingletonFactory
。- 后面的兩個(gè)方法都比較簡單,主要是
getSingleton
的操作,它是一層層處理不同時(shí)期的單例對(duì)象,直至拿到有效的對(duì)象。
- 后面的兩個(gè)方法都比較簡單,主要是
3.4 提前暴露對(duì)象
3.4.1 實(shí)例化感知對(duì)象處理
InstantiationAwareBeanPostProcessor.java
package com.lino.springframework.beans.factory.config;import com.lino.springframework.beans.BeansException;
import com.lino.springframework.beans.PropertyValues;/*** @description: 實(shí)例化感知對(duì)象處理*/
public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor {.../*** 在 Spring 中由 SmartInstantiationAwareBeanPostProcessor#getEarlyBeanReference 提供** @param bean 對(duì)象* @param beanName 對(duì)象名稱* @return 二級(jí)緩存對(duì)象*/default Object getEarlyBeanReference(Object bean, String beanName) {return bean;}
}
- 添加
getEarlyBeanReference
緩存二級(jí)緩存對(duì)象方法
3.4.2 默認(rèn)自動(dòng)代理創(chuàng)建者
DefaultAdvisorAutoProxyCreator.java
package com.lino.springframework.aop.framework.autoproxy;import com.lino.springframework.aop.*;
import com.lino.springframework.aop.aspectj.AspectJExpressionPointcutAdvisor;
import com.lino.springframework.aop.framework.ProxyFactory;
import com.lino.springframework.beans.BeansException;
import com.lino.springframework.beans.PropertyValues;
import com.lino.springframework.beans.factory.BeanFactory;
import com.lino.springframework.beans.factory.BeanFactoryAware;
import com.lino.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
import com.lino.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.aopalliance.aop.Advice;
import org.aopalliance.intercept.MethodInterceptor;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;/*** @description: 默認(rèn)自動(dòng)代理創(chuàng)建者*/
public class DefaultAdvisorAutoProxyCreator implements InstantiationAwareBeanPostProcessor, BeanFactoryAware {private DefaultListableBeanFactory beanFactory;private final Set<Object> earlyProxyReferences = Collections.synchronizedSet(new HashSet<>());@Overridepublic void setBeanFactory(BeanFactory beanFactory) throws BeansException {this.beanFactory = (DefaultListableBeanFactory) beanFactory;}@Overridepublic Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {return null;}@Overridepublic boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {return true;}private boolean isInfrastructureClass(Class<?> beanClass) {return Advice.class.isAssignableFrom(beanClass) || Pointcut.class.isAssignableFrom(beanClass) || Advisor.class.isAssignableFrom(beanClass);}@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {return bean;}@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {if (!earlyProxyReferences.contains(beanName)) {return wrapIfNecessary(bean, beanName);}return bean;}protected Object wrapIfNecessary(Object bean, String beanName) {if (isInfrastructureClass(bean.getClass())) {return bean;}Collection<AspectJExpressionPointcutAdvisor> advisors = beanFactory.getBeansOfType(AspectJExpressionPointcutAdvisor.class).values();for (AspectJExpressionPointcutAdvisor advisor : advisors) {ClassFilter classFilter = advisor.getPointcut().getClassFilter();// 過濾匹配類if (!classFilter.matches(bean.getClass())) {continue;}AdvisedSupport advisedSupport = new AdvisedSupport();TargetSource targetSource = new TargetSource(bean);advisedSupport.setTargetSource(targetSource);advisedSupport.setMethodInterceptor((MethodInterceptor) advisor.getAdvice());advisedSupport.setMethodMatcher(advisor.getPointcut().getMethodMatcher());advisedSupport.setProxyTargetClass(true);// 返回代理對(duì)象return new ProxyFactory(advisedSupport).getProxy();}return bean;}@Overridepublic Object getEarlyBeanReference(Object bean, String beanName) {earlyProxyReferences.add(beanName);return wrapIfNecessary(bean, beanName);}@Overridepublic PropertyValues postProcessPropertyValues(PropertyValues pvs, Object bean, String beanName) throws BeansException {return pvs;}
}
3.4.3 實(shí)現(xiàn)默認(rèn)bean創(chuàng)建的抽象bean工廠超類
AbstractAutowireCapableBeanFactory.java
package com.lino.springframework.beans.factory.support;import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.lino.springframework.beans.BeansException;
import com.lino.springframework.beans.PropertyValue;
import com.lino.springframework.beans.PropertyValues;
import com.lino.springframework.beans.factory.*;
import com.lino.springframework.beans.factory.config.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;/*** @description: 實(shí)現(xiàn)默認(rèn)bean創(chuàng)建的抽象bean工廠超類*/
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory implements AutowireCapableBeanFactory {private InstantiationStrategy instantiationStrategy = new SimpleInstantiationStrategy();@Overrideprotected Object createBean(String beanName, BeanDefinition beanDefinition, Object[] args) throws BeansException {// 判斷是否返回代理 Bean 對(duì)象Object bean = resolveBeforeInstantiation(beanName, beanDefinition);if (null != bean) {return bean;}return doCreateBean(beanName, beanDefinition, args);}protected Object doCreateBean(String beanName, BeanDefinition beanDefinition, Object[] args) {Object bean = null;try {// 實(shí)例化Beanbean = createBeanInstance(beanDefinition, beanName, args);// 處理循環(huán)依賴,將實(shí)例化后的Bean對(duì)象提前放入緩存中暴露出來if (beanDefinition.isSingleton()) {Object finalBean = bean;addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, beanDefinition, finalBean));}// 實(shí)例化后判斷boolean continueWithPropertyPopulation = applyBeanPostProcessorsAfterInstantiation(beanName, bean);if (!continueWithPropertyPopulation) {return bean;}// 在設(shè)置Bean屬性之前,允許 BeanPostProcessor修改屬性值applyBeanPostProcessorsBeforeApplyingPropertyValues(beanName, bean, beanDefinition);// 給bean填充屬性applyPropertyValues(beanName, bean, beanDefinition);// 執(zhí)行 Bean 的初始化方法和 BeanPostProcessor 的前置和后置處理方法bean = initializeBean(beanName, bean, beanDefinition);} catch (Exception e) {throw new BeansException("Instantiation of bean failed", e);}// 注冊(cè)實(shí)現(xiàn) DisposableBean 接口的 Bean 對(duì)象registerDisposableBeanIfNecessary(beanName, bean, beanDefinition);// 判斷 SCOPE_SINGLETON、SCOPE_PROTOTYPEObject exposedObject = bean;if (beanDefinition.isSingleton()) {// 獲取代理對(duì)象exposedObject = getSingleton(beanName);registerSingletonBean(beanName, exposedObject);}return exposedObject;}protected Object getEarlyBeanReference(String beanName, BeanDefinition beanDefinition, Object bean) {Object exposedObject = bean;for (BeanPostProcessor beanPostProcessor : getBeanPostProcessors()) {if (beanPostProcessor instanceof InstantiationAwareBeanPostProcessor) {exposedObject = ((InstantiationAwareBeanPostProcessor) beanPostProcessor).getEarlyBeanReference(exposedObject, beanName);if (null == exposedObject) {return exposedObject;}}}return exposedObject;}...
}
- 在
AbstractAutowireCapableBeanFactory#doCreateBean
的方法中主要是擴(kuò)展了對(duì)象的提前暴露addSingletonFactory
,和單例對(duì)象的獲取getSingleton
,以及注冊(cè)操作registerSingletonBean
。 getEarlyBeanReference
方法就是定義在如 AOP 切面中這樣的代理對(duì)象。
四、測試:通過三級(jí)緩存解決循環(huán)依賴
4.1 添加測試配置
4.1.1 老公類
Husband.java
package com.lino.springframework.test.bean;/*** @description: 老公類*/
public class Husband {private Wife wife;public String queryWife() {return "Husband.wife";}public Wife getWife() {return wife;}public void setWife(Wife wife) {this.wife = wife;}
}
4.1.2 媳婦類
Wife.java
package com.lino.springframework.test.bean;/*** @description: 媳婦類*/
public class Wife {private Husband husband;private IMother mother;public String queryHusband() {return "Wife.husband、Mother.callMother: " + mother.callMother();}public Husband getHusband() {return husband;}public void setHusband(Husband husband) {this.husband = husband;}public IMother getMother() {return mother;}public void setMother(IMother mother) {this.mother = mother;}
}
4.1.3 婆婆接口
IMother.java
package com.lino.springframework.test.bean;/*** @description: 婆婆接口*/
public interface IMother {String callMother();
}
4.1.4 婆婆代理類
HusbandMother.java
package com.lino.springframework.test.bean;import com.lino.springframework.beans.factory.FactoryBean;
import java.lang.reflect.Proxy;/*** @description: 老公婆婆類*/
public class HusbandMother implements FactoryBean<IMother> {@Overridepublic IMother getObject() throws Exception {return (IMother) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class[]{IMother.class},(proxy, method, args) -> "婚后媳婦媽媽的職責(zé)被婆婆代理了!" + method.getName());}@Overridepublic Class<?> getObjectType() {return IMother.class;}@Overridepublic boolean isSingleton() {return true;}
}
4.1.5 切面
SpouseAdvice.java
package com.lino.springframework.test.bean;import com.lino.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;/*** @description: 攔截器*/
public class SpouseAdvice implements MethodBeforeAdvice {@Overridepublic void before(Method method, Object[] args, Object target) throws Throwable {System.out.println("關(guān)懷小兩口(切面):" + method);}
}
4.1.6 Spring屬性配置文件
spring.xml
<?xml version="1.0" encoding="utf-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="husband" class="com.lino.springframework.test.bean.Husband"><property name="wife" ref="wife"/></bean><bean id="husbandMother" class="com.lino.springframework.test.bean.HusbandMother"/><bean id="wife" class="com.lino.springframework.test.bean.Wife"><property name="husband" ref="husband"/><property name="mother" ref="husbandMother"/></bean><!--AOP 配置,驗(yàn)證三級(jí)緩存 --><bean class="com.lino.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/><bean id="beforeAdvice" class="com.lino.springframework.test.bean.SpouseAdvice"/><bean id="methodInterceptor" class="com.lino.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor"><property name="advice" ref="beforeAdvice"/></bean><bean id="pointcutAdvisor" class="com.lino.springframework.aop.aspectj.AspectJExpressionPointcutAdvisor"><property name="expression" value="execution(* com.lino.springframework.test.bean.Wife.*(..))"/><property name="advice" ref="methodInterceptor"/></bean></beans>
4.2 單元測試
ApiTest.java
@Test
public void test_autoProxy() {ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:spring.xml");Husband husband = applicationContext.getBean("husband", Husband.class);Wife wife = applicationContext.getBean("wife", Wife.class);System.out.println("老公的媳婦:" + husband.queryWife());System.out.println("媳婦的老公:" + wife.queryHusband());
}
測試結(jié)果
老公的媳婦:Husband.wife
關(guān)懷小兩口(切面):public java.lang.String com.lino.springframework.test.bean.Wife.queryHusband()
媳婦的老公:Wife.husband、Mother.callMother: 婚后媳婦媽媽的職責(zé)被婆婆代理了!callMother
- 測試結(jié)果看,無論是簡單對(duì)象依賴,還是代理工程對(duì)象,或者 AOP 切面對(duì)象,都可以在三級(jí)緩存下解決循環(huán)依賴的問題。
- 此外從運(yùn)行截圖
DefaultSingletonBeanRegistry#getSingleton
中也可以看到需要三級(jí)緩存存放工廠對(duì)象的類,都會(huì)使用到getObject
獲取真實(shí)對(duì)象,并隨后存入半成品對(duì)象earlySingletonObjects
中以及移除工廠對(duì)象。
五、總結(jié):通過三級(jí)緩存解決循環(huán)依賴
- Spring 中所有的功能都是以解決 Java 編程中的特性而存在的,就像我們處理的循環(huán)依賴,如果沒有 Spring 框架的情況下,可能我們也會(huì)盡可能避免寫出循環(huán)依賴的操作,因?yàn)樵跊]有經(jīng)過加工處理后,這樣的依賴關(guān)系肯定會(huì)報(bào)錯(cuò)的。
- 這也是程序從 能用 到 好用 的升級(jí)。
- 在解決循環(huán)依賴的核心流程中,主要是提前暴露對(duì)象的設(shè)計(jì),以及建立三級(jí)緩存的數(shù)據(jù)結(jié)構(gòu)來存放不同時(shí)期的對(duì)象。
- 如果說沒有如切面和工廠中的代理對(duì)象,那么二級(jí)緩存也就可以解決了,哪怕是只有一級(jí)緩存。
- 但為了設(shè)計(jì)上的合理和可擴(kuò)展性,所以創(chuàng)建了三級(jí)緩存來放置不同時(shí)期的對(duì)象。