從 Spring IOC 容器中獲取 bean 實例的流程:從context.getBean()方法開始
發(fā)生了循環(huán)依賴:
public class A {
@Autowired
private B b;
}
public class B {
@Autowired
private A a;
}
獲取單例
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
//從一級緩存(單例池)中查找對象
Object singletonObject = this.singletonObjects.get(beanName);
//單例池中找不到半沽,而且被查找的bean正在創(chuàng)建中--發(fā)生了循環(huán)依賴
//通過singletonsCurrentlyInCreation(set)記錄對象是否正在被創(chuàng)建
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
//從二級緩存中去尋找 原始對象或者是代理對象
singletonObject = this.earlySingletonObjects.get(beanName);
//二級緩存中找不到 就去三級緩存中找
if (singletonObject == null && allowEarlyReference) {
//這里取得三級緩存中對應的lambda表達式的值--得到原始對象(發(fā)生循環(huán)依賴但未aop)或者是代理對象(發(fā)生循環(huán)依賴和aop--提前aop)
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
//執(zhí)行上一步獲取的lambda表達式(getEarlyBeanReference方法)
//--有aop,就提前執(zhí)行AOP--得到一個代理對象
//-- 無aop腕唧,就得到一個原始對象
singletonObject = singletonFactory.getObject();// 提前曝光 bean 實例(raw bean)翎朱,用于解決循環(huán)依賴
//將通過三級緩存得到的結果 放入二級緩存
this.earlySingletonObjects.put(beanName, singletonObject);
//移除三級緩存中對應的內容
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
三級緩存為什么會移除掉?
在三級緩存中找 找到了就會執(zhí)行AOp 產出代理對象 然后將代理對象放入到二級緩存忌堂。三級緩存一定會能到的對象 但不一定 會執(zhí)行 aop 二級緩存找不到 才會觸發(fā)aop(通過lambda表達式盒至,執(zhí)行函數式接口,執(zhí)行aop) 產生代理對象放入二級緩存士修,放入之后需要移除掉對應的三級緩存(保證只執(zhí)行一次aop)如果三級緩存中對象不需要執(zhí)行aop操作 枷遂,那么產生的對象仍然要放入二級緩存 ,這是放入的對象是原始對象
為什么單例池:concurentHashmap是李命,二級緩存是hashmap登淘,三級緩存是hashmap?
三級緩存的AOP過程需要加鎖以保證操作的原子性
因為三級緩存的函數接口 內部已經加了鎖封字,保證了操作的原子性 所以沒必要使用concurenthashmap
問題:源碼中加synchronized鎖的意義?
背景:
二級緩存中的aService對象是三級緩存中的lambda表達式生成出來的耍鬓,
他們是成對的阔籽,二級緩存中存在代理對象,則三級緩存中不應該存在lambda表達式牲蜀;
或者說笆制,三級緩存中存在lambda表達式,則二級緩存中不應當有該代理對象
解答:
- 3級緩存中的 value是一個lambda表達式涣达,一執(zhí)行就是進行AOP在辆,得到代理對象,所以lambda表達式應當只執(zhí)行一次度苔,且執(zhí)行完畢后從3級緩存中進行移除匆篓,以防止其他的代碼又拿出來執(zhí)行了
- 在第2、第3級緩存只能有一個地方存在操作對象寇窑,要么是lambda表達式(三級緩存)鸦概,要么是lambda執(zhí)行后的代理對象(二級緩存)。這是原子性的甩骏,為了對高并發(fā)情況進行控制窗市,加鎖進行同步先慷。
- 1級緩存定義為 concurrentHashMap。 2級咨察、3級緩存定義為簡單的HashMap论熙,是因為 2、3級緩存是成對出現的摄狱,哪怕是定義成concurrentHashMap脓诡,也要加鎖保持兩個Map的操作的原子性
創(chuàng)建Bean
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
// Instantiate the bean.
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
//得到原始對象 -- 屬性未賦值
final Object bean = instanceWrapper.getWrappedInstance();
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}
// Allow post-processors to modify the merged bean definition.
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Post-processing of merged bean definition failed", ex);
}
mbd.postProcessed = true;
}
}
// Eagerly cache singletons to be able to resolve circular references
// even when triggered by lifecycle interfaces like BeanFactoryAware.
//如果當前創(chuàng)建的是單例bean,并且允許著環(huán)依賴,并且還在創(chuàng)建過程中二蓝,那么則提早暴露--一般均為true
//創(chuàng)建就暴露--一般單例都會暴露出去--都會存入三級緩存
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isTraceEnabled()) {
logger.trace("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
//針對發(fā)生了循環(huán)依賴的情況
//lambda執(zhí)行的結果存入三級緩存中
//getEarlyBeanReference--wrapIfNecessary方法--判斷對象創(chuàng)建過程中是否存在AOP
//--需要誉券,就提前aop,存入代理對象,不需要就存入原始對象
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
// Initialize the bean instance.
//暴露原始對象
Object exposedObject = bean;
try {
//屬性填充@Autowired --B對象填充原始對象
populateBean(beanName, mbd, instanceWrapper);
//正常情況下進行AOP的地方--postProcessAfterInitialization方法
// --判斷是否提前進行了AOP(使用Map:earlyProxyReferences記錄提前 進行的aop)刊愚,如果沒有提前aop踊跟,才會在這里執(zhí)行aop
//初始化Bean--可能包含AOP--如果需要AOP,則需要使用原始對象(針對非循環(huán)依賴的時候)
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
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);
}
}
····················
// Register bean as disposable.
try {
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
}
return exposedObject;
}
其中:
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
是將原始對象信息存入三級緩存的操作,存入的是lambda表達式:
getEarlyBeanReference(beanName, mbd, bean)執(zhí)行的結果,getEarlyBeanReference會對是否需要提前AOP進行判斷鸥诽,如果需要進行AOP商玫,則生成代理對象放入二級緩存。
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(singletonFactory, "Singleton factory must not be null");
synchronized (this.singletonObjects) {
if (!this.singletonObjects.containsKey(beanName)) {
this.singletonFactories.put(beanName, singletonFactory);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
}
其中:
exposedObject = initializeBean(beanName, exposedObject, mbd);
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
invokeAwareMethods(beanName, bean);
return null;
}, getAccessControlContext());
}
else {
invokeAwareMethods(beanName, bean);
}
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
//對類中某些特殊方法的調用牡借,比如 @PostConstruct拳昌,Aware接口
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
//InitializingBean接口,afterPropertiesSet钠龙,init-method屬性調用
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}
if (mbd == null || !mbd.isSynthetic()) {
//AOP入口
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
整個流程:
1炬藤、A doCreateBean()初始化,由于還未創(chuàng)建碴里,從一級緩存查不到沈矿,此時只是一個半成品(提前暴露的對象),放入三級緩存singletonFactories;
2咬腋、A發(fā)現自己需要B對象羹膳,但是三級緩存中未發(fā)現B,創(chuàng)建B的原始對象根竿,將帶有B對象信息(beanName,bd,原始對象)的Lambda表達式放入singletonFactories;
3陵像、B發(fā)現自己需要A對象,從一級緩存singletonObjects沒找到寇壳,并知道了A對象正在創(chuàng)建醒颖,就確認發(fā)生了循環(huán)依賴,這時候再去二級緩存earlySingletonObjects中尋找A對象九巡,沒找到就繼續(xù)在三級緩存singletonFactories中尋找A對象(一定能找到)图贸,于是執(zhí)行三級緩存中的lambda表達式得到一個代理對象或者是原始對象A(A中屬性未賦值),將A放入二級緩存earlySingletonObjects,同時從三級緩存刪除對應beanName的表達式疏日;
同理向三級緩存加入對象時偿洁,也會從二級緩存中將相同BeanName的記錄刪除掉,所以二級緩存與三級緩存的之間的來兩步操作具有原子性沟优。
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
4涕滋、將A注入到對象B中;
5挠阁、B完成屬性填充宾肺,執(zhí)行初始化方法,將自己放入第一級緩存中(此時B是一個完整的對象)侵俗;
6锨用、A得到對象B,將B注入到A中隘谣;
7增拥、A完成屬性填充,初始化寻歧,并放入到一級緩存中
注意:在對象創(chuàng)建開始的時候掌栅,會對對象創(chuàng)建狀態(tài)利用Set:
singletonsCurrentlyInCreation進行記錄:是否是正在創(chuàng)建,可用于判斷是否發(fā)生了循環(huán)依賴。
@Lazy注解的作用:
initializeBean
Spring解決循環(huán)依賴問題--B站視頻講解
Spring 循環(huán)依賴的“常見”面試問題