這篇文章主要講解了“Spring Ioc中Bean的加載實(shí)現(xiàn)方法”,文中的講解內(nèi)容簡(jiǎn)單清晰,易于學(xué)習(xí)與理解,下面請(qǐng)大家跟著小編的思路慢慢深入,一起來(lái)研究和學(xué)習(xí)“Spring Ioc中Bean的加載實(shí)現(xiàn)方法”吧!
創(chuàng)新互聯(lián)公司-專業(yè)網(wǎng)站定制、快速模板網(wǎng)站建設(shè)、高性價(jià)比秀英網(wǎng)站開發(fā)、企業(yè)建站全套包干低至880元,成熟完善的模板庫(kù),直接使用。一站式秀英網(wǎng)站制作公司更省心,省錢,快速模板網(wǎng)站建設(shè)找我們,業(yè)務(wù)覆蓋秀英地區(qū)。費(fèi)用合理售后完善,十多年實(shí)體公司更值得信賴。
代碼:
//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. //判斷需要?jiǎng)?chuàng)建的Bean是否可以實(shí)例化,即是否可以通過當(dāng)前的類加載器加載 Class> resolvedClass = resolveBeanClass(mbd, beanName); if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) { mbdToUse = new RootBeanDefinition(mbd); mbdToUse.setBeanClass(resolvedClass); } // Prepare method overrides. //校驗(yàn)和準(zhǔn)備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配置了初始化前和初始化后的處理器,則試圖返回一個(gè)需要?jiǎng)?chuàng)建Bean的代理對(duì)象 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 { //創(chuàng)建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); } }
這段代碼分為以下幾個(gè)步驟:
判斷需要?jiǎng)?chuàng)建的Bean是否可以實(shí)例化,即是否可以通過當(dāng)前的類加載器加載
校驗(yàn)和準(zhǔn)備Bean中的方法注入
如果Bean配置了初始化前和初始化后的處理器,則試圖返回一個(gè)需要?jiǎng)?chuàng)建Bean的代理對(duì)象
創(chuàng)建Bean
主要是獲取bean的class,并設(shè)置到BeanDefinition中
主要是處理方法注入
代碼:
public void prepareMethodOverrides() throws BeanDefinitionValidationException { // Check that lookup methods exists. //檢測(cè)是否存在方法注入,并循環(huán)預(yù)處理方法注入 if (hasMethodOverrides()) { Setoverrides = getMethodOverrides().getOverrides(); synchronized (overrides) { //遍歷處理 for (MethodOverride mo : overrides) { prepareMethodOverride(mo); } } } }
prepareMethodOverride(mo):
protected void prepareMethodOverride(MethodOverride mo) throws BeanDefinitionValidationException { // 統(tǒng)計(jì)注入的方法個(gè)數(shù) 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,則將注入方法標(biāo)記為未重載 // 注意:當(dāng)有多個(gè)重載方法時(shí),為了確定調(diào)用哪個(gè)具體的方法,Spring對(duì)重載方法的參數(shù)解析是很復(fù)雜的 // 所以,如果注入方法沒有被重載這里就將其標(biāo)記,省去了對(duì)方法參數(shù)的解析過程,直接調(diào)用即可 else if (count == 1) { // Mark override as not overloaded, to avoid the overhead of arg type checking. mo.setOverloaded(false); } }
代碼讀到這里,大家可能有疑問,從代碼上看明明是處理的方法重載,但是為什么處理的是方法注入呢?而且如果我們?cè)赽ean里設(shè)置幾個(gè)方法重載的話,hasMethodOverrides()
方法返回的是false。如果我們打開 AbstractBeanDefinition 類的 hasMethodOverrides() 方法,就能打消我們之前的疑問。
public boolean hasMethodOverrides() { return (this.methodOverrides != null && !this.methodOverrides.isEmpty()); }
其中methodOverrides
是做什么的呢?通過類名AbstractBeanDefinition我們可以發(fā)現(xiàn),該類是BeanDefinition的一個(gè)子類,那么它保存的應(yīng)該是我們解析到的beanDefinition,spring在解析配置文件的時(shí)候,如果發(fā)現(xiàn)配置了replace-method
或者lookup-method
那么,就會(huì)對(duì)應(yīng)的標(biāo)簽解析,并存入到 AbstractBeanDefinition 的 methodOverrides 屬性中,那么當(dāng)bean實(shí)例化的時(shí)候,如果檢測(cè)到了methodOverrides屬性不為空,則動(dòng)態(tài)的為當(dāng)前bean生成代理并使用相應(yīng)的攔截器對(duì)bean做處理,這里大家只要把概念搞清楚即可。
主要是對(duì)bean前置后置處理器的處理,給 BeanPostProcessors 后置處理器一個(gè)返回代理對(duì)象的機(jī)會(huì)
詳細(xì)代碼:
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; }
如果代理對(duì)象不為空,則直接返回代理對(duì)象,這一步驟有非常重要的作用,Spring 后續(xù)實(shí)現(xiàn) AOP 就是基于這個(gè)地方判斷的。
這個(gè)方法核心就在于 applyBeanPostProcessorsBeforeInstantiation()
和 applyBeanPostProcessorsAfterInitialization()
兩個(gè)方法,before 為實(shí)例化前的后處理器應(yīng)用,after 為實(shí)例化后的后處理器應(yīng)用。
doCreateBean()
創(chuàng)建Bean
//真正創(chuàng)建Bean的方法 protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args) throws BeanCreationException { // Instantiate the bean. //BeanWrapper是對(duì)Bean的包裝,其接口中所定義的功能很簡(jiǎn)單包括設(shè)置獲取被包裝的對(duì)象,獲取被包裝bean的屬性描述器 BeanWrapper instanceWrapper = null; if (mbd.isSingleton()) { //單例模式,刪除factoryBean緩存 instanceWrapper = this.factoryBeanInstanceCache.remove(beanName); } if (instanceWrapper == null) { //使用合適的實(shí)例化策略來(lái)創(chuàng)建Bean:工廠方法、構(gòu)造函數(shù)自動(dòng)注入、簡(jiǎn)單初始化 instanceWrapper = createBeanInstance(beanName, mbd, args); } //從包裝類中獲取實(shí)例化的Bean final Object bean = instanceWrapper.getWrappedInstance(); //獲取實(shí)例化對(duì)象的類型 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 { //調(diào)用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. // 解決單例模式的循環(huán)依賴 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"); } //這里是一個(gè)匿名內(nèi)部類,為了防止循環(huán)引用,盡早持有對(duì)象的引用 addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean)); } // Initialize the bean instance. //Bean對(duì)象的初始化,依賴注入在此觸發(fā) //這個(gè)exposedObject在初始化完成之后返回作為依賴注入完成后的Bean Object exposedObject = bean; try { //將Bean實(shí)例對(duì)象封裝,并且Bean定義中配置的屬性值賦值給實(shí)例對(duì)象 populateBean(beanName, mbd, instanceWrapper); //初始化Bean對(duì)象 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) { //獲取指定名稱的已注冊(cè)的單例模式Bean對(duì)象 Object earlySingletonReference = getSingleton(beanName, false); if (earlySingletonReference != null) { //根據(jù)名稱獲取的已注冊(cè)的Bean和正在實(shí)例化的Bean是同一個(gè) if (exposedObject == bean) { //當(dāng)前實(shí)例化的Bean初始化完成 exposedObject = earlySingletonReference; } //當(dāng)前Bean依賴其他Bean,并且當(dāng)發(fā)生循環(huán)引用時(shí)不允許新創(chuàng)建實(shí)例對(duì)象 else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) { String[] dependentBeans = getDependentBeans(beanName); SetactualDependentBeans = new LinkedHashSet<>(dependentBeans.length); //獲取當(dāng)前Bean所依賴的其他Bean for (String dependentBean : dependentBeans) { //對(duì)依賴Bean進(jìn)行類型檢查 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. //注冊(cè)完成依賴注入的Bean try { registerDisposableBeanIfNecessary(beanName, bean, mbd); } catch (BeanDefinitionValidationException ex) { throw new BeanCreationException( mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex); } return exposedObject; }
代碼很長(zhǎng),不過別慌,我們來(lái)按步驟分析一波
如果是單例模式,從factoryBeanInstanceCache 緩存中獲取BeanWrapper 實(shí)例對(duì)象并刪除緩存
調(diào)用 createBeanInstance()
實(shí)例化 bean
(主要是將 BeanDefinition 轉(zhuǎn)換為 BeanWrapper)
后置處理
單例模式的循環(huán)依賴處理
初始化 bean 實(shí)例對(duì)象
(屬性填充)
依賴檢查
注冊(cè) DisposableBean
doCreateBean()
完成 bean 的創(chuàng)建和初始化工作,內(nèi)容太多,比較復(fù)雜,這里只列出大致流程,接下來(lái)我們將分幾篇文章來(lái)分別闡述相關(guān)內(nèi)容。
感謝各位的閱讀,以上就是“Spring Ioc中Bean的加載實(shí)現(xiàn)方法”的內(nèi)容了,經(jīng)過本文的學(xué)習(xí)后,相信大家對(duì)Spring Ioc中Bean的加載實(shí)現(xiàn)方法這一問題有了更深刻的體會(huì),具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是創(chuàng)新互聯(lián),小編將為大家推送更多相關(guān)知識(shí)點(diǎn)的文章,歡迎關(guān)注!