中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Spring Ioc中Bean的加載實現方法

發布時間:2021-06-24 09:22:45 來源:億速云 閱讀:151 作者:chen 欄目:大數據

這篇文章主要講解了“Spring  Ioc中Bean的加載實現方法”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“Spring  Ioc中Bean的加載實現方法”吧!


createBean()

代碼:

//AbstractAutowireCapableBeanFactory.java

protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
		throws BeanCreationException {

	if (logger.isDebugEnabled()) {
		logger.debug("Creating instance of bean '" + beanName + "'");
	}
	RootBeanDefinition mbdToUse = mbd;

	// Make sure bean class is actually resolved at this point, and
	// clone the bean definition in case of a dynamically resolved Class
	// which cannot be stored in the shared merged bean definition.
	//判斷需要創建的Bean是否可以實例化,即是否可以通過當前的類加載器加載
	Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
	if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
		mbdToUse = new RootBeanDefinition(mbd);
		mbdToUse.setBeanClass(resolvedClass);
	}

	// Prepare method overrides.
	//校驗和準備Bean中的方法覆蓋
	try {
		mbdToUse.prepareMethodOverrides();
	}
	catch (BeanDefinitionValidationException ex) {
		throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
				beanName, "Validation of method overrides failed", ex);
	}

	try {
		// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
		//如果Bean配置了初始化前和初始化后的處理器,則試圖返回一個需要創建Bean的代理對象
		Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
		if (bean != null) {
			return bean;
		}
	}
	catch (Throwable ex) {
		throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
				"BeanPostProcessor before instantiation of bean failed", ex);
	}

	try {
		//創建Bean的入口
		Object beanInstance = doCreateBean(beanName, mbdToUse, args);
		if (logger.isDebugEnabled()) {
			logger.debug("Finished creating instance of bean '" + beanName + "'");
		}
		return beanInstance;
	}
	catch (BeanCreationException ex) {
		// A previously detected exception with proper bean creation context already...
		throw ex;
	}
	catch (ImplicitlyAppearedSingletonException ex) {
		// An IllegalStateException to be communicated up to DefaultSingletonBeanRegistry...
		throw ex;
	}
	catch (Throwable ex) {
		throw new BeanCreationException(
				mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
	}
	}

這段代碼分為以下幾個步驟:

  1. 判斷需要創建的Bean是否可以實例化,即是否可以通過當前的類加載器加載

  2. 校驗和準備Bean中的方法注入

  3. 如果Bean配置了初始化前和初始化后的處理器,則試圖返回一個需要創建Bean的代理對象

  4. 創建Bean

第1步

主要是獲取bean的class,并設置到BeanDefinition中

第2步

主要是處理方法注入
代碼:

public void prepareMethodOverrides() throws BeanDefinitionValidationException {
	// Check that lookup methods exists.
	//檢測是否存在方法注入,并循環預處理方法注入
	if (hasMethodOverrides()) {
		Set<MethodOverride> overrides = getMethodOverrides().getOverrides();
		synchronized (overrides) {
		        //遍歷處理
			for (MethodOverride mo : overrides) {
				prepareMethodOverride(mo);
			}
		}
	}
	}

prepareMethodOverride(mo):

protected void prepareMethodOverride(MethodOverride mo) throws BeanDefinitionValidationException {
        // 統計注入的方法個數   
	int count = ClassUtils.getMethodCountForName(getBeanClass(), mo.getMethodName());
	if (count == 0) {
		throw new BeanDefinitionValidationException(
				"Invalid method override: no method with name '" + mo.getMethodName() +
				"' on class [" + getBeanClassName() + "]");
	}
        // 如果為1,則將注入方法標記為未重載
	// 注意:當有多個重載方法時,為了確定調用哪個具體的方法,Spring對重載方法的參數解析是很復雜的
	// 所以,如果注入方法沒有被重載這里就將其標記,省去了對方法參數的解析過程,直接調用即可
	else if (count == 1) {
		// Mark override as not overloaded, to avoid the overhead of arg type checking.
		mo.setOverloaded(false);
	}
	}

代碼讀到這里,大家可能有疑問,從代碼上看明明是處理的方法重載,但是為什么處理的是方法注入呢?而且如果我們在bean里設置幾個方法重載的話,hasMethodOverrides()方法返回的是false。如果我們打開 AbstractBeanDefinition 類的 hasMethodOverrides() 方法,就能打消我們之前的疑問。

public boolean hasMethodOverrides() {
		return (this.methodOverrides != null && !this.methodOverrides.isEmpty());
	}

其中methodOverrides是做什么的呢?通過類名AbstractBeanDefinition我們可以發現,該類是BeanDefinition的一個子類,那么它保存的應該是我們解析到的beanDefinition,spring在解析配置文件的時候,如果發現配置了replace-method或者lookup-method那么,就會對應的標簽解析,并存入到 AbstractBeanDefinition 的 methodOverrides 屬性中,那么當bean實例化的時候,如果檢測到了methodOverrides屬性不為空,則動態的為當前bean生成代理并使用相應的攔截器對bean做處理,這里大家只要把概念搞清楚即可。

第3步

主要是對bean前置后置處理器的處理,給 BeanPostProcessors 后置處理器一個返回代理對象的機會
詳細代碼:

protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
	Object bean = null;
	if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
		// Make sure bean class is actually resolved at this point.
		if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
			Class<?> targetType = determineTargetType(beanName, mbd);
			if (targetType != null) {
				bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
				if (bean != null) {
					bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
				}
			}
		}
		mbd.beforeInstantiationResolved = (bean != null);
	}
	return bean;
	}

如果代理對象不為空,則直接返回代理對象,這一步驟有非常重要的作用,Spring 后續實現 AOP 就是基于這個地方判斷的。
這個方法核心就在于 applyBeanPostProcessorsBeforeInstantiation()applyBeanPostProcessorsAfterInitialization() 兩個方法,before 為實例化前的后處理器應用,after 為實例化后的后處理器應用。

第4步

doCreateBean()
創建Bean

//真正創建Bean的方法
	protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
		throws BeanCreationException {

	// Instantiate the bean.
	//BeanWrapper是對Bean的包裝,其接口中所定義的功能很簡單包括設置獲取被包裝的對象,獲取被包裝bean的屬性描述器
	BeanWrapper instanceWrapper = null;
	if (mbd.isSingleton()) {
	        //單例模式,刪除factoryBean緩存
		instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
	}
	if (instanceWrapper == null) {
	        //使用合適的實例化策略來創建Bean:工廠方法、構造函數自動注入、簡單初始化
		instanceWrapper = createBeanInstance(beanName, mbd, args);
	}
	//從包裝類中獲取實例化的Bean
	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 {
			        //調用PostProcessor后置處理器,修改 BeanDefinition
				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.isDebugEnabled()) {
			logger.debug("Eagerly caching bean '" + beanName +
					"' to allow for resolving potential circular references");
		}
		//這里是一個匿名內部類,為了防止循環引用,盡早持有對象的引用
		addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
	}

	// Initialize the bean instance.
	//Bean對象的初始化,依賴注入在此觸發
	//這個exposedObject在初始化完成之后返回作為依賴注入完成后的Bean
	Object exposedObject = bean;
	try {
		//將Bean實例對象封裝,并且Bean定義中配置的屬性值賦值給實例對象
		populateBean(beanName, mbd, instanceWrapper);
		//初始化Bean對象
		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) {
		//獲取指定名稱的已注冊的單例模式Bean對象
		Object earlySingletonReference = getSingleton(beanName, false);
		if (earlySingletonReference != null) {
			//根據名稱獲取的已注冊的Bean和正在實例化的Bean是同一個
			if (exposedObject == bean) {
				//當前實例化的Bean初始化完成
				exposedObject = earlySingletonReference;
			}
			//當前Bean依賴其他Bean,并且當發生循環引用時不允許新創建實例對象
			else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
				String[] dependentBeans = getDependentBeans(beanName);
				Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
				//獲取當前Bean所依賴的其他Bean
				for (String dependentBean : dependentBeans) {
					//對依賴Bean進行類型檢查
					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.
	//注冊完成依賴注入的Bean
	try {
		registerDisposableBeanIfNecessary(beanName, bean, mbd);
	}
	catch (BeanDefinitionValidationException ex) {
		throw new BeanCreationException(
				mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
	}

	return exposedObject;
	}

代碼很長,不過別慌,我們來按步驟分析一波

  1. 如果是單例模式,從factoryBeanInstanceCache 緩存中獲取BeanWrapper 實例對象并刪除緩存

  2. 調用 createBeanInstance() 實例化 bean
    (主要是將 BeanDefinition 轉換為 BeanWrapper)

  3. 后置處理

  4. 單例模式的循環依賴處理

  5. 初始化 bean 實例對象
    (屬性填充)

  6. 依賴檢查

  7. 注冊 DisposableBean

doCreateBean() 完成 bean 的創建和初始化工作,內容太多,比較復雜,這里只列出大致流程,接下來我們將分幾篇文章來分別闡述相關內容。

感謝各位的閱讀,以上就是“Spring  Ioc中Bean的加載實現方法”的內容了,經過本文的學習后,相信大家對Spring  Ioc中Bean的加載實現方法這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

乌兰浩特市| 越西县| 乌恰县| 加查县| 封开县| 永泰县| 宽甸| 临湘市| 远安县| 宁武县| 伊宁县| 攀枝花市| 伊金霍洛旗| 营口市| 汶上县| 旬邑县| 阳谷县| 东兰县| 姚安县| 航空| 侯马市| 扎囊县| 新兴县| 六盘水市| 都兰县| 台东县| 八宿县| 靖西县| 德保县| 冷水江市| 邢台市| 阜宁县| 武夷山市| 城固县| 海阳市| 承德县| 延长县| 云和县| 金川县| 杭锦后旗| 青川县|