從之前的ioc部分的源碼分析等,我們對spring-ioc部分的相關已經有了一部分認識和了解,但是還是有很多人對裏面一些部分的理解還是很模糊,好比既然有了beanFactory那factoryBean是幹什麼的,在ioc中有很多相關的aware這種後綴的類的命名,感覺應該有聲明上的相似,但是卻可能在之前的文章都一筆帶過了…
鑑於諸如此類的,我想通過demo的方式,從表現形式上來區分所謂的beanFactory和FactoryBean,以及aware這類的意義
BeanFactory與FactoryBean
對於FactoryBean而言,想要體現factoryBean的強大的話,需結合AOP才能體現出來其強大,這裏我們先初步分析,留待之後與AOP結合分析,爲什麼要與AOP結合分析,我們先看看官方描述
出自FactoryBean官方註釋說明: A bean that implements this interface cannot be used as a normal bean. A FactoryBean is defined in a bean style, but the object exposed for bean references ({@link #getObject()}) is always the object that it creates. This interface is heavily used within the framework itself, for example for the AOP {@link org.springframework.aop.framework.ProxyFactoryBean} or the {@link org.springframework.jndi.JndiObjectFactoryBean}. It can be used for custom components as well; however, this is only common for infrastructure code. 雖然FactoryBean定義爲一個bean的形式,但是會通過getObject方法將一些對象暴露出來,我們可以通過ProxyFactoryBean的getObject中先了解下可知任何實現了beanFactory的bean都可通過getObject獲取這個類型的bean 官方在AOP的ProxyFactoryBean或JndiObjectFactoryBean中有這兩個類可作爲示例,接口是在框架內大量使用,也能被使用在自定義的組建,然後這個僅在基礎結構代碼中常見
上一篇咱們簡單的提及了factoryBean, 我們藉助beanFactory通過"&"+beanName的方法查找class,現在我們就看下spring對這塊的官方說明
即在beanFactory中有這一個說明,就是其通過&這個符號來獲取factoryBean,到此factoryBean我們就瞭解到,其FactoryBean的getObject()返回的對象,而不是FactoryBean本身, 如果要獲取FactoryBean對象,可以在id前面加一個&符號來獲取
廢話不多說直接上實例:
首先我們既然要看factorybean,那我們就實現一個,既然官方爲我們提供了ProxyFactoryBean和JndiObjectFactoryBean中兩個類作爲示例,那我們就從示例中類比寫出一個簡單的factoryBean來印證
-
實現factorybean接口
public class ProxyMyFactoryBean implements FactoryBean { public Object getObject() throws Exception { return null; } public Class<?> getObjectType() { return null; } public boolean isSingleton() { return false; } }
-
factoryBean中只有三個方法,我們一邊結合官方註釋和官方示例的ProxyFactoryBean來"豐滿"各個方法
-
getObject方法
官方的描述是這樣的"返回一個在factory中被管理的類的實例"
-
isSingleton()方法
即在factory中被管理的類是否是單例的
在ProxyFactoryBean中其實現的getObject()的方法用了以上兩個方法
我們不關心其中間的實現,我們就關注其返回結果,可發現,如果是單例的話,就通過創建單例的方式創建一個實例返回,否則的話,就直接創建一個對象返回
-
getObjectType方法
可瞭解其是返回factoryBean創建的實例的類型,可能有些人跟我一樣理解不了要這玩意兒幹啥,我們再看看其具體描述"這個方法允許在不實例化對象的情況下檢查特定類型的bean,例如在autowiring時",感覺有點用還是不太清楚,看看示例輔助下
從這裏我們也關注其返回的結果,
- 單例實例時,就返回該實例的class對象,否則的話獲取代理接口,
- 如果是一個的多就返回該代理接口的class對象
- 如果是多個的話就創建一個組合接口的class對象
- 如果targetName不爲null且beanFactory不爲null就從beanFactory中找到tagetName的class類型返回
- 如果均不符合,那就返回targetSource的class
簡單理解就是返回我們getObject創建實例的關聯類的class
-
-
"豐滿"我們的factoryBean
-
準備工作,由於其是返回示例所以我們需要創建類來輔助我們
public class TargetA { public void print() { System.out.println("-----print--AAA----succeed---"); } } public class TargetB { public void print() { System.out.println("-----print--BBB----succeed---"); } }
-
"豐滿”工作
public class ProxyMyFactoryBean implements FactoryBean { private String targetName; public void setTargetName(String targetName) { this.targetName = targetName; } public Object getObject() throws Exception { if("aaa".equals(targetName)) { return new TargetA(); } return new TargetB(); } public Class<?> getObjectType() { if("aaa".equals(targetName)) { return TargetA.class; } return TargetB.class; } public boolean isSingleton() { return false; } }
-
創建bean的xml配置factorybean信息
<bean id="proxyMyFactoryBean" class="org.tutor.spring.ioc.bean.ProxyMyFactoryBean"> <property name="targetName" value="aaa"/> </bean>
-
運行結果
從其運行結果我們都能獲取到targetA的實例用以操控
-
-
總結
beanFactory就不在此處詳細介紹,不過我們做一下從上面運行的方式,我們都能看到無論beanFactory還是FactoryBean我們都能獲取我們想要的實例對象
-
beanFactory相當於bean的容器,可以理解成工廠,內可以幫我們創建bean,對bean進行管理
-
factoryBean雖然也可以創建bean,其更多的是對class上進行代理處理,從我們的測試方法,我們很容易就可以想到,明顯代理的痕跡
這裏我引用一張圖加以理解
就是我們通過設置目標的class屬性從factoryBean中獲取目標class的代理對象
可能有人會疑問爲什麼會有這樣的設計,其實spring在aop中已經回答我們,不過我們也可以從代理模式的優點能理解其意義也是可以
- 在符合開閉原則的情況下對目標對象進行功能擴展
那麼我們就可以大膽的猜想,其就是爲了讓我們在持有目標對象時,豐富對象功能,也可以不在關注具象實現,有需求方關注(具體我們在AOP處,對ProxyFactoryBean的應用處可瞭解)
-
BeanNameAware與BeanFactoryAware
BeanNameAware是對於需要獲取在beanFactory的beanName的時候就實現
BeanFactoryAware是由對應的BeanFactory實現的,即可獲取該bean所在的beanFactory名稱,可以獲取配置他們的BeanFactory的引用
總結
由於BeanNameAware和BeanFactoryAware均都是spring內實現,故其實對我們應用及其有限,但它們對spring而言,卻不一樣,我們可以從spring代碼書寫來理解
-
BeanNameAware
類似這樣,本身springLifeBean沒有什麼意義,只是我們做的一個標記,便於理解
-
BeanFactoryAware
這個方法可能是在根據某個配置文件創建了一個新工廠之後,Spring才調用這個方法,並把BeanFactory注入到Bean中。
讓bean獲取配置自己的工廠之後,當然可以在Bean中使用這個工廠的getBean()方法,但是,實際上非常不推薦這樣做,因爲結果是進一步加大Bean與Spring的耦合,而且,能通過DI注入進來的儘量通過DI來注入。
當然,除了查找bean,BeanFactory可以提供大量其他的功能,例如銷燬singleton模式的Bean。
factory.preInstantiateSingletons();方法。preInstantiateSingletons()方法立即實例化所有的Bean實例,有必要對這個方法和Spring加載bean的機制做個簡單說明。
方法本身的目的是讓Spring立即處理工廠中所有Bean的定義,並且將這些Bean全部實例化。因爲Spring默認實例化Bean的情況下,採用的是lazy機制,換言之,如果不通過getBean()方法(BeanFactory或者ApplicationContext的方法)獲取Bean的話,那麼爲了節省內存將不實例話Bean,只有在Bean被調用的時候才實例化它們引用自網上對BeanFactoryAware的描述
Springbean的初始化順序
對於IOC我們也分析有一段時間了,既然IOC是對bean的操作,那麼我們還沒有正面關注過,接下來,通過bean的初始化過程,繼續鞏固一路走來的IOC分析
在我們分析SpringFactory的refresh時候,其依次順序是aware 然後InitializingBean,最後進入的是postProcessor,那我們通過實現這些接口看看其的順序是否跟我們的refresh分析是否相左
-
準備工作
創建一個類,實現’BeanFactoryAware,BeanNameAware,BeanFactoryPostProcessor,BeanPostProcessor,InitializingBean’這些接口
public class TestLifeCycleBean implements BeanFactoryAware,BeanNameAware,BeanFactoryPostProcessor,BeanPostProcessor,InitializingBean { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } public TestLifeCycleBean() { System.out.println("into... 構造函數"); } /** * init-method */ public void initMethod(){ System.out.println("into... init-method"); } public void say(){ System.out.println("into... say hello I am "+name); } public void setBeanFactory(BeanFactory beanFactory) throws BeansException { System.out.println("into... setBeanFactory and beanFactory is "+beanFactory); } public void setBeanName(String s) { System.out.println("into... setBeanName and name is "+s); } public void afterPropertiesSet() throws Exception { System.out.println("into... InitializingBean接口的afterPropertiesSet and name is "+ name); } public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException { System.out.println("into... BeanFactoryPostProcessor接口的postProcessBeanFactory and this beanFactory is "+configurableListableBeanFactory); } public Object postProcessBeforeInitialization(Object o, String s) throws BeansException { System.out.println("into... BeanPostProcessor接口的postProcessBeforeInitialization: "+o.getClass()); return o; } public Object postProcessAfterInitialization(Object o, String s) throws BeansException { System.out.println("into... BeanPostProcessor接口的postProcessAfterInitialization: "+o.getClass()); return o; } }
在這裏可能我們打印的結果可能是這樣的
很明顯BeanPostProcessor的相關方法並沒有產生作用,這是我們之前的大戰BeanPostProcessor有說明,我們只用實例化一個bean即可
總結其springbean的初始化順序
- 1.先執行構造函數
- 2.之行BeanNameAware方法
- 3.執行BeanFactoryAware方法
- 4.之行InitializingBean方法
- 5.執行指定的init-method方法
- 6.執行BeanFactoryPostProcessor方法
- 7.最後纔有BeanPostProcessor方法
回顧之前的refresh
有沒有豁然開朗的感覺?!就先整理這些吧,持續整理更新…