前端 JavaScript 中的三種 for 迴圈語句總結
spring是如何解決迴圈依賴問題
簡單總結版(A類和B類迴圈引用):
1.獲取A類時,一級快取singletonObjects獲取不到,並且正在建立set(singletonsCurrentlyInCreation)中沒有A類
2.從二級快取(earlySingletonObjects)中獲取,還是沒有
3.三級快取singletonFactories存放的都是繼承了ObjectFactory的物件,有個getObject方法,通過lambda執行呼叫匿名函式中的createBean()
4.通過createBean() -->docreateBean()建立類(選擇哪個建構函式的程式碼在這),並將A放進三級快取(同時從二級快取刪除)(如果mbd.isSingleton() && this.allowCircularReferences)
5.如果A需要代理,提前生成代理,後續把注入的bean換成代理Bean
5.然後populateBean填充屬性B
6.例項化B,將B放入三級快取
7.B類getSingleton(A)從三級快取中獲取到A的工廠,呼叫工廠的getObject()獲取到A,然後把A從三級快取刪除,放到二級快取
8建立B成功,返回A
8.A建立成功
三級快取放的是生成A的
DefaultSingletonBeanRegistry有三個快取map
/** Cache of singleton objects: bean name to bean instance. */ //用於存放完全初始化好的 bean從該快取中取出的 bean可以直接使用 一級快取 private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256); /** Cache of singleton factories: bean name to ObjectFactory. */ //存放 bean工廠物件解決迴圈依賴 三級快取 private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16); /** Cache of early singleton objects: bean name to bean instance. */ //存放原始的bean物件用於解決迴圈依賴,注意:存到裡面的物件還沒有被填充屬性 二級快取 private final Map<String, Object> earlySingletonObjects = new HashMap<>(16); private final Set<String> singletonsCurrentlyInCreation = Collections.newSetFromMap(new ConcurrentHashMap<>(16));
假如A類有成員變數B b;B類有成員變數A a,屬於迴圈依賴的情況
1.A類建立bean的時候呼叫getBean(a) ---> 回撥doCreateBean(a) --> populateBean(b) --> resolveDependency(b) --> doResovleDependency(b) --> resovleCandidate(b) --> getBean(b)
2.A類在呼叫getBean(a)方法的時候就通過DefaultSingletonBeanRegistry.getSingleton(a)從一級快取(singletonObjects)中獲取,一級快取獲取不到同時A也沒有在singletonsCurrentlyInCreation
3.因為A沒有沒生成,所以就開始建立A
3.addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));//getEarlyBeanReference獲取的就是A的代理類
A的代理類在doCreateBean(a)的時候就加入到(三級快取)singletonFactories,並刪除二級快取裡的代理A(其實也沒有)
4.B類被A類依賴,開始初始化getBean(b) --> doCreateBean(b) --> populateBean(a) --> resolveDependency(a) --> doResovleDependency(a) --> resovleCandidate() --> getBean(a)
5.B執行到這裡已經和A執行到第2步一樣了,這時候從三級快取中獲取到了A的代理類,將A從三級快取刪除放到二級快取(earlySingletonObjects)當中並返回A
6.移除:addSingleton、addSingletonFactory、removeSingleton
從語義中可以看出新增單例、新增單例工廠ObjectFactory
的時候都會刪除二級快取裡面對應的快取值,是互斥的
AbstractBeanFactory.doGetBean(a)中開始初始化A類
1.當A類開始初始化bean執行AbstranctBeanFactory.doGetBean(a),並第一次呼叫AbstractBeanFactory.getBean(a) --> DefaultSingletonBeanRegistry.getSingleton(String beanName, boolean allowEarlyReference)
一級快取(singletonObjects)沒有A,並且isSingletonCurrentlyInCreation(beanName)(這裡是在後面的getSingleton方法裡面加入的)也是false,所以返回null
DefaultSingletonBeanRegistry.protected Object getSingleton(String beanName, boolean allowEarlyReference)
/**
* Return the (raw) singleton object registered under the given name.
* <p>Checks already instantiated singletons and also allows for an early
* reference to a currently created singleton (resolving a circular reference).
* @param beanName the name of the bean to look for
* @param allowEarlyReference whether early references should be created or not
* @return the registered singleton object, or {@code null} if none found
*/
//本方法主要用來處理迴圈依賴
/**
* allowEarlyReference引數的含義是Spring是否允許迴圈依賴,預設為true
* 所以當allowEarlyReference設定為false的時候,當專案存在迴圈依賴,會啟動失敗
*/
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
//從map中獲取bean如果不為空直接返回,不再進行初始化工作
//本方法主要用於程式設計師在外部使用annotationConfigApplicationContext.getBean()的時候使用
/**
* 1.按照程式碼的邏輯,我們第一次呼叫到這裡的時候,記錄正在建立的bean的set裡面是空的,所以isSingletonCurrentlyInCreation(beanName)返回false
* 所以本次getSingleton返回null
* 2.第二次呼叫的是下面的getSingleton(String beanName, ObjectFactory<?> singletonFactory)方法
* spring已經做了該做的驗證,如果為空則建立物件
*/
Object singletonObject = this.singletonObjects.get(beanName);
//如果從singletonObjects取不到bean,並且正在建立當中
//!!!!!!!!!!!!!!!!!!!!第一次執行到這裡就返回Null了
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
singletonObject = this.earlySingletonObjects.get(beanName);
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;
}
2.然後doGetBean中判斷返回的sharedInstance為null,執行DefaultSingletonBeanRegistry.getSingleton(String beanName, ObjectFactory<?> singletonFactory),注意兩個getsingleton引數不一樣。這時A的beanName通過beforeSingletonCreation(beanName);被放入singletonsCurrentlyInCreation這個set
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(beanName, "Bean name must not be null");
synchronized (this.singletonObjects) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
if (this.singletonsCurrentlyInDestruction) {
throw new BeanCreationNotAllowedException(beanName,
"Singleton bean creation not allowed while singletons of this factory are in destruction " +
"(Do not request a bean from a BeanFactory in a destroy method implementation!)");
}
if (logger.isDebugEnabled()) {
logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
}
/**
* 將beanName新增到singletonsCurrentlyInCreation這樣一個集合中
* 表示beanName對應的bean正在建立中
*/
beforeSingletonCreation(beanName);
boolean newSingleton = false;
boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
if (recordSuppressedExceptions) {
this.suppressedExceptions = new LinkedHashSet<>();
}
try {
//在這裡建立bean 這裡下一步是呼叫的是lambda表示式return createBean(beanName, mbd, args);
singletonObject = singletonFactory.getObject();
newSingleton = true;
}
catch (IllegalStateException ex) {
// Has the singleton object implicitly appeared in the meantime ->
// if yes, proceed with it since the exception indicates that state.
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
throw ex;
}
}
catch (BeanCreationException ex) {
if (recordSuppressedExceptions) {
for (Exception suppressedException : this.suppressedExceptions) {
ex.addRelatedCause(suppressedException);
}
}
throw ex;
}
finally {
if (recordSuppressedExceptions) {
this.suppressedExceptions = null;
}
afterSingletonCreation(beanName);
}
if (newSingleton) {
addSingleton(beanName, singletonObject);
}
}
return singletonObject;
}
}
3.繼續執行doGetBean() --> AbstractAutowireCapableBeanFactory.createBean() --> AbstractAutowireCapableBeanFactory.doCreateBean()
在doCreateBean()當中通過createBeanInstance()方法反射建立物件
然後在isSingletonCurrentlyInCreation(beanName)方法中判斷當前beanName是否被加到singletonsCurrentlyInCreation這個set當中,剛才第2步已經新增完了
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) {
/**
* 建立 bean 例項,並將例項包裹在 BeanWrapper 實現類物件中返回。
* createBeanInstance中包含三種建立 bean 例項的方式:
* 1. 通過工廠方法建立 bean 例項
* 2. 通過構造方法自動注入(autowire by constructor)的方式建立 bean 例項
* 3. 通過無參構造方法方法建立 bean 例項
*
* 若 bean 的配置資訊中配置了 lookup-method 和 replace-method,則會使用 CGLIB
* 增強 bean 例項。關於lookup-method和replace-method後面再說。
*/
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.
//判斷
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");
}
//把bean從DefaultSingletonBeanRegistry.earlySingletonObjects中移除
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
// Initialize the bean instance.
//這是時候還是原生的bean物件
Object exposedObject = bean;
try {
//設定屬性,非常重要
populateBean(beanName, mbd, instanceWrapper);
//執行後置處理器,aop就是在這裡完成的處理!!!
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);
}
}
if (earlySingletonExposure) {
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
}
else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
String[] dependentBeans = getDependentBeans(beanName);
Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
for (String dependentBean : dependentBeans) {
if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
actualDependentBeans.add(dependentBean);
}
}
if (!actualDependentBeans.isEmpty()) {
throw new BeanCurrentlyInCreationException(beanName,
"Bean with name '" + beanName + "' has been injected into other beans [" +
StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
"] in its raw version as part of a circular reference, but has eventually been " +
"wrapped. This means that said other beans do not use the final version of the " +
"bean. This is often the result of over-eager type matching - consider using " +
"'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
}
}
}
}
// Register bean as disposable.
try {
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
}
return exposedObject;
}
4.往三級快取singletonFactories新增beanName資料,並移除二級快取earlySingletonObjects中的beanName
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);
//把bean從earlySingletonObjects移除
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
}
ObjectFactory是一個介面,只有一個方法getObject ,符合lambda表示式的,下面的程式碼就是實現這個介面,實際上是呼叫@EnableAspectJAutoProxy註解匯入的AnnotationAwareAspectJAutoProxyCreator。可以直接理解為返回了一個A的物件
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;
}
5.生成物件以後通過AbstractAutowireCapableBeanFactory.populateBean填充物件屬性
我們從populateBean()方法的autowireByType()方法去看。這時候需要填充A的屬性,發現需要B類,呼叫DefaultLisatableBeanFactory.resolveDependency(b) --> getBean(b)初始化B類
6.當B類填充屬性A時,再次呼叫getSingleton(String beanName, boolean allowEarlyReference)
這一次呼叫getSingleton邏輯就不一樣了,singletonObject一級快取中還是獲取不到,二級快取earlySingletonObjects也獲取不到,然後從三級快取中能獲取到上面第4步放到singletonFactories中的未完全初始化的a物件。
刪除三級快取的資料,將a物件放到二級快取,返回a物件
//本方法主要用來處理迴圈依賴
/**
* allowEarlyReference引數的含義是Spring是否允許迴圈依賴,預設為true
* 所以當allowEarlyReference設定為false的時候,當專案存在迴圈依賴,會啟動失敗
*/
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
//從map中獲取bean如果不為空直接返回,不再進行初始化工作
//本方法主要用於程式設計師在外部使用annotationConfigApplicationContext.getBean()的時候使用
/**
* 1.按照程式碼的邏輯,我們第一次呼叫到這裡的時候,記錄正在建立的bean的set裡面是空的,所以isSingletonCurrentlyInCreation(beanName)返回false
* 所以本次getSingleton返回null
* 2.第二次呼叫的是下面的getSingleton(String beanName, ObjectFactory<?> singletonFactory)方法
* spring已經做了該做的驗證,如果為空則建立物件
*/
Object singletonObject = this.singletonObjects.get(beanName);
//如果從singletonObjects取不到bean,並且正在建立當中
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
singletonObject = this.earlySingletonObjects.get(beanName);
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;
}
https://www.jianshu.com/p/16a44c25c9d9
https://javazhiyin.blog.csdn.net/article/details/107602783
通俗易懂的三級快取解釋迴圈依賴https://blog.csdn.net/f641385712/article/details/92801300
迴圈依賴代理提前暴露講解https://blog.csdn.net/u012098021/article/details/107352463