1. 程式人生 > 其它 >前端 JavaScript 中的三種 for 迴圈語句總結

前端 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

這個set當中

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