初探一下Spring的整個核心精神 - IOC
1. org.springframework.beans
BeanFactory 介面提供了更進階的設定機制用來管理各種object.
2. org.springframework.context
ApplicationContext則是繼承了BeanFactory,並加入了更容易於整合Spring AOP的功能,像是
message resource handling , event publication , application-layer context , 以及web applicaiton常需要的webApplicationContext.
ApplicationContext的主要角色當然就是做為物件的初始化、參數設定,以及整合管理物件之間的使用關係,
這一切都是直接透過 XML metadata / java annotation / java code 設定完成。
常見用來做為設定的有ClassPathXmlApplicaitonContext / FileSystemXmlApplicationContext
來個簡單的XML metadata
3. Bean instantiation ~
這裡開始見到一些常見的Design pattern用法了,Spring在處理物件初始話時,選用了 static factory method,透過<bean> tag宣告,
告知IOC container 去找到正確需要被呼叫的 factory method,整體的細節實作在更後面的章節會提到,先貼個sample來過過癮。
<bean id="clientService" factory-method="createInstance"/>
public class ClientService {
private static ClientService clientService = new ClientService();
private ClientService() {}
public static ClientService createInstance() {
return clientService;
}
}
除了上述的還有instance factory method
每一個bean在宣告設定時,是可以有多個factory method的!!
<bean id="serviceLocator">
<!-- inject any dependencies required by this locator bean -->
</bean>
<bean id="clientService" factory-bean="serviceLocator" factory-method="createClientServiceInstance"/>
<bean id="accountService" factory-bean="serviceLocator" factory-method="createAccountServiceInstance"/>
4. Dependencies
DI,簡單講就是一個專門來處理個實體之間的相互關係的process,透過DI來處理各個物件實體之間是如何運作的,
大致上有使用三種方式來進行 [ constructor / arg to factory method / setter ],
透過設定的方式來降低各個物件中的高度相依關係,同時也使得各項物件便於進行測試,每一個物件甚至根本不會知道彼此依存的物件的存在@@"
在Spring 中建議的方式是:Constructor-based dependency injection & Setter-based dependency injection
# Constructor-based DI
透過建構子的方式進行注入的工作是把必要得參數傳入由container執行,當然這也等同於使用statis factory method來運作!! 以下範例說明僅提供Constructor DI
public class A {
private String name;
public A(String name){ this.name = name;}
}
如果遇到constructor傳入參數眾多時,Container將自動進行ambigiously type checking, 不會去管參數傳入順序,只要找到傳入參數型別相符的,
就會使用該種宣告的bean 定義 ( ex , 傳入 HashMap , LinkList 但與bean tag中宣告兩者相反順序), 當然也可以指定出現順序,如下範例:
<bean id="exampleBean">
<constructor-arg index="0" value="7500000"/>
<constructor-arg index="1" value="42"/>
</bean>
# Setter-based DI
透過Setter方式,是在bean實體化之後再進行的,當然一定是會搭配一個non-arg public constructor作宣告
ApplicationContext支援Constructor-Based / Setter-Based DI
那麼我們到底要用哪一種? Spring 建議使用Setter DI,因為過多的參數處理會讓你得寫一拖拉庫的factory method,
尤其是遇到有很多參數是非必要的,那就麻煩了!! 但這只是建議,必要時是得看真實情形去設計。
# Circular dependencies lead to BeanCurrentlyCreationException
當定義class A instance 與 class B instance 彼此之間透過 constructor injection互相參考時,很容易發生這種問題,要避免這種問題就是選擇使用Setter DI(且也是唯一解)。
Spring IOC container會在load-time進行所有的設定檢查,包括那些不存在的bean 定義以及circular dependencies,
但在設定相依性的部分則會較晚發生( lazy binding ?),這邊也就是說部會在一開始container load時就會將所有物件的錯誤全數引發,會在當你去要一個bean instance時,假設有exception才會丟出..
#bean 定義特殊說明
<bean id="" name="" factory-method="" > --> 使用factory method的只有在constructor DI方式下才有,Setter DI沒有
<constructor-arg />--> Constructor DI使用
<property /> --> Setter DI 使用
</bean>
參考到其他的bean時,可以使用以下方法
<bean id="theTargetBean" />
<bean id="client">
<property name="targetName" value="theTargetBean" />
</bean>
但Spring建議使用以下方法
<bean id="theTargetBean"/>
<bean id="theClientBean">
<property name="targetName">
<idref bean="theTargetBean" />
</property>
</bean>
原因是使用後者的方法時,IOC container可以在deploy time去做驗證確認bean instance是否已經存在,而前者則完全無法進行驗證
# ref element in <constructor-arg> or <property>
<ref bean=""> --> 可以在不同的xml 定義檔中reference
<ref local=""> --> 僅能在同一個xml 定義檔中reference
<ref parent=""> --> 這部分主要是可以透過不同的iocContainer來存取parent container 的bean
# Inner beans ,這部分設定產出的其實就是巢狀的<bean> tag,只是他只能是anonymous class,且不需要id / name,bean scope 只會是prototype (每一個物件實體各自存在)
# Lazy-initialized beans,預設的ApplicationContext是會自動的將大部份的singleton bean 進行初始化,若要避免此問題 可在<bean lazy-init="true">即可關閉,
當然若要針對整個container層級進行設定,也可在<beans default-lazy-init="true">進行設定。
沒有留言:
張貼留言