5.5 准备创建bean
5.5??準備創建bean
?
我們不可能指望在一個函數中完成一個復雜的邏輯,而且我們跟蹤了這么多Spring代碼,經歷了這么多函數,或多或少也發現了一些規律:一個真正干活的函數其實是以do開頭的,比如doGetObjectFromFactoryBean;而給我們錯覺的函數,比如getObjectFromFactoryBean,其實只是從全局角度去做些統籌的工作。這個規則對于createBean也不例外,那么讓我們看看在createBean函數中做了哪些準備工作。
?
1 protected Object createBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) throws BeanCreationException { 2 3 if (logger.isDebugEnabled()) { 4 logger.debug("Creating instance of bean '" + beanName + "'"); 5 } 6 //鎖定class,根據設置的class屬性或者根據className來解析Class 7 resolveBeanClass(mbd, beanName); 8 9 //驗證及準備覆蓋的方法 10 try { 11 mbd.prepareMethodOverrides(); 12 } 13 catch (BeanDefinitionValidationException ex) { 14 throw new BeanDefinitionStoreException(mbd.getResourceDescription(), 15 beanName, "Validation of method overrides failed", ex); 16 } 17 18 try { 19 //給BeanPostProcessors一個機會來返回代理來替代真正的實例 20 Object bean = resolveBeforeInstantiation(beanName, mbd); 21 if (bean != null) { 22 return bean; 23 } 24 } 25 catch (Throwable ex) { 26 throw new BeanCreationException(mbd.getResourceDescription(), beanName, 27 "BeanPostProcessor before instantiation of bean failed", ex); 28 } 29 30 Object beanInstance = doCreateBean(beanName, mbd, args); 31 if (logger.isDebugEnabled()) { 32 logger.debug("Finished creating instance of bean '" + beanName + "'"); 33 } 34 return beanInstance; 35 }?
從代碼中我們可以總結出函數完成的具體步驟及功能。
(1)根據設置的class屬性或者根據className來解析Class。
(2)對override屬性進行標記及驗證。
很多讀者可能會不知道這個方法的作用,因為在Spring的配置里面根本就沒有諸如override-method之類的配置,那么這個方法到底是干什么用的呢?
其實在Spring中確實沒有override-method這樣的配置,但是如果讀過前面的部分,可能會有所發現,在Spring配置中是存在lookup-method和replace-method的,而這兩個配置的加載其實就是將配置統一存放在BeanDefinition中的methodOverrides屬性里,而這個函數的操作其實也就是針對于這兩個配置的。
(3)應用初始化前的后處理器,解析指定bean是否存在初始化前的短路操作。
(4)創建bean。
我們首先查看下對override屬性標記及驗證的邏輯實現。
?
處理ovverride屬性
?
查看源碼中AbstractBeanDefinition類的prepareMethodOverrides方法:
?
1 public void prepareMethodOverrides() throws BeanDefinitionValidationException { 2 // Check that lookup methods exists. 3 MethodOverrides methodOverrides = getMethodOverrides(); 4 if (!methodOverrides.isEmpty()) { 5 for (MethodOverride mo : methodOverrides.getOverrides()) { 6 prepareMethodOverride(mo); 7 } 8 } 9 } 10 protected void prepareMethodOverride(MethodOverride mo) throws BeanDefinitionValidationException { 11 //獲取對應類中對應方法名的個數 12 int count = ClassUtils.getMethodCountForName(getBeanClass(), mo.getMethodName()); 13 if (count == 0) { 14 throw new BeanDefinitionValidationException( 15 "Invalid method override: no method with name '" + mo.getMethodName() + 16 "' on class [" + getBeanClassName() + "]"); 17 } 18 else if (count == 1) { 19 //標記MethodOverride暫未被覆蓋,避免參數類型檢查的開銷。 20 mo.setOverloaded(false); 21 } 22 }?
通過以上兩個函數的代碼你能體會到它所要實現的功能嗎?之前反復提到過,在Spring配置中存在lookup-method和replace-method兩個配置功能,而這兩個配置的加載其實就是將配置統一存放在BeanDefinition中的methodOverrides屬性里,這兩個功能實現原理其實是在bean實例化的時候如果檢測到存在methodOverrides屬性,會動態地為當前bean生成代理并使用對應的攔截器為bean做增強處理,相關邏輯實現在bean的實例化部分詳細介紹。
但是,這里要提到的是,對于方法的匹配來講,如果一個類中存在若干個重載方法,那么,在函數調用及增強的時候還需要根據參數類型進行匹配,來最終確認當前調用的到底是哪個函數。但是,Spring將一部分匹配工作在這里完成了,如果當前類中的方法只有一個,那么就設置重載該方法沒有被重載,這樣在后續調用的時候便可以直接使用找到的方法,而不需要進行方法的參數匹配驗證了,而且還可以提前對方法存在性進行驗證,正可謂一箭雙雕。
5.5.2??實例化的前置處理
在真正調用doCreate方法創建bean的實例前使用了這樣一個方法resolveBeforeInstantiation?(beanName,?mbd)對BeanDefinigiton中的屬性做些前置處理。當然,無論其中是否有相應的邏輯實現我們都可以理解,因為真正邏輯實現前后留有處理函數也是可擴展的一種體現,但是,這并不是最重要的,在函數中還提供了一個短路判斷,這才是最為關鍵的部分。
?
if (bean != null) {return bean; }?
當經過前置處理后返回的結果如果不為空,那么會直接略過后續的Bean的創建而直接返回結果。這一特性雖然很容易被忽略,但是卻起著至關重要的作用,我們熟知的AOP功能就是基于這里的判斷的。
?
1 protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) { 2 Object bean = null; 3 //如果尚未被解析 4 if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) { 5 // Make sure bean class is actually resolved at this point. 6 if (mbd.hasBeanClass() && !mbd.isSynthetic() && hasInstantiationAware BeanPostProcessors()) { 7 bean = applyBeanPostProcessorsBeforeInstantiation(mbd.getBeanClass(), beanName); 8 if (bean != null) { 9 bean = applyBeanPostProcessorsAfterInitialization(bean, beanName); 10 } 11 } 12 mbd.beforeInstantiationResolved = (bean != null); 13 } 14 return bean; 15 }?
此方法中最吸引我們的無疑是兩個方法applyBeanPostProcessorsBeforeInstantiation以及applyBeanPostProcessorsAfterInitialization。兩個方法實現的非常簡單,無非是對后處理器中的所有InstantiationAwareBeanPostProcessor類型的后處理器進行postProcessBeforeInstantiation方法和BeanPostProcessor的postProcessAfterInitialization方法的調用。
1.實例化前的后處理器應用
bean的實例化前調用,也就是將AbsractBeanDefinition轉換為BeanWrapper?前的處理。給子類一個修改BeanDefinition的機會,也就是說當程序經過這個方法后,bean可能已經不是我們認為的bean了,而是或許成為了一個經過處理的代理bean,可能是通過cglib生成的,也可能是通過其它技術生成的。這在第7章中會詳細介紹,我們只需要知道,在bean的實例化前會調用后處理器的方法進行處理。
?
1 protected Object applyBeanPostProcessorsBeforeInstantiation(Class beanClass, String beanName) 2 throws BeansException { 3 4 for (BeanPostProcessor bp : getBeanPostProcessors()) { 5 if (bp instanceof InstantiationAwareBeanPostProcessor) { 6 InstantiationAwareBeanPostProcessor ibp = (Instantiation AwareBean PostProcessor) bp; 7 Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName); 8 if (result != null) { 9 return result; 10 } 11 } 12 } 13 return null; 14 }?
2.實例化后的后處理器應用
在講解從緩存中獲取單例bean的時候就提到過,Spring中的規則是在bean的初始化后盡可能保證將注冊的后處理器的postProcessAfterInitialization方法應用到該bean中,因為如果返回的bean不為空,那么便不會再次經歷普通bean的創建過程,所以只能在這里應用后處理器的postProcessAfterInitialization方法。
?
1 public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName) 2 throws BeansException { 3 4 Object result = existingBean; 5 for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) { 6 result = beanProcessor.postProcessAfterInitialization(result, beanName); 7 if (result == null) { 8 return result; 9 } 10 } 11 return result; 12 }?
?
?
?
?
?
?
?
?
?
總結
以上是生活随笔為你收集整理的5.5 准备创建bean的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 第二次装OA系统
- 下一篇: /etc/sudoers中的含义