- Wiring bean with Java
- 建議使用@Component及@Autowired
- 問題
- 將3rd party library的component做autowired到application,這種時候就無法在3rd-party的class上加上@Component及@Autowired
- 解法
- 採用顯示configuration。可以使用Java或XML
- 使用Java設置configuration
- 不該包含業務邏輯
- 僅是一個configuration file
- 通常會放到單獨的package內,藉此與其他的application logic分開,對他的用途不會造成困擾
- 建立Configuration class
- 必須在class內新增一annotation @Configuration例:
package soundsystem; import org.springframework.context.annotation.Configuration; @Configuration // key word public class CDPlayerConfig { }
- 注意此java config class應該要包含bean的create detail
- 若沒有@ConponentScan annotation時,將不會找到component,create bean會失敗
- 解法:在JavaConfig中declare bean
@Bean // 告知會return object,且要註冊為Spring application context的bean public CompactDisc sgtPeppers() { //default bean id和method name一致 return new SgtPeppers(); // 會創建所需class instance }
- 若要重新命名,在跨括號內寫名字 @Bean(name="lonelyHeartsClubBand")
- 有injection時:
@Bean public CDPlayer cdPlayer() { // ID: cdPlayer return new CDPlayer(sgtPeppers()); // Spring直接return創建的bean,而不是每次都呼叫 }
- 與原本Java method的差異
- 使用method: 每次都會有回傳一個新的sgtPeppers instance
- 使用@Bean:每次呼叫sgtPeppers()instance都會是相同的
- Spring中的bean都是singletons,因此Spring直接return創建的bean,而不是每次都呼叫。
- 有injection時也可以寫成
@Bean public CDPlayer cdPlayer(CompactDisc compactDisc) { //這種寫法會autowired CimpactDisc,不用明確的引用@Bean CompactDisc return new CDPlayer(compactDisc); }
- 使用XML設置configuration - 一種舊式的配置方式
- 建立Configuration
- 以<beans>為root,如
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context">
xmlns:c="http://www.springframework.org/schema/c" <!-- c namespace使用-->
xmlns:p="http://www.springframework.org/schema/p" <!-- p namespace使用-->
- xmlns:util="http://www.springframework.org/schema/util" <!-- util-namespace使用-->
</beans>
- 可以藉由STS的File>New>Spring Bean Configuration File create
- 要declare一個bean,需要使用<bean>,就像是JavaConfig中的@Bean annotation,如:
<bean id="compactDisc" class="soundsystem.SgtPeppers" /> <!-- 必須是fully qualified class name-->
- 自動產生的ID為fully qualified class name#,如上:soundsystem.SgtPeppers#0,但如果有寫上id attribute,則ID就會是id key的value。當然只需要對需要ID引用的bean來確切命名即可
- 和Java configuration的差異
- 不需要負責create SgtPeppers instance,XML檔發現bean element會直接call SgtPeppers的constructor以create bean,也就是JavaConfig內可以使用任何方式來new bean instance
- 需要注意xml內的class是以String帶入,不是type-safe,可能會打錯字(可以靠強大的IDE解決,幫忙檢查)
- 使用constructor injection實體化bean
- 在XML declare DI有兩種基本方式
- <constructor-arg> :較冗長
- c-namespace:<constructor-arg> 能做到的c-namespace不一定能做到
- 範例,當Spring遇到<bean>,會create CDPlayer instance,然後看到<constructor-arg,就會將compactDisc bean reference傳入constructor
<bean id="cdPlayer" class="soundsystem.CDPlayer"> <constructor-arg ref="compactDisc" /> //透過ID使用SgtPeppers </bean>
- 使用c-namespace 優點簡潔
<bean id="cdPlayer" class="soundsystem.CDPlayer" c:cd-ref="compactDisc" />
- c : prefix
- cd : constructor argument name
- ref: injecting a bean,告知Spring是一個bean reference
- compactDisc: injecting bean ID
- 如果不想使用constructor argument name,也可以使用parameter的位置表達
<bean id="cdPlayer" class="soundsystem.CDPlayer" c:_0-ref="compactDisc" /> <--!表示argument第0的index-->
- 如果只有一個argument,也可以不用加index。如c:_-ref="compactDisc"
- Injecting constructors withe literal value
- 範例:假如有一BlankDisc實作了CompactDisc
package soundsystem; public class BlankDisc implements CompactDisc { private String title; private String artist; public BlankDisc(String title, String artist) { //兩個arguments this.title = title; this.artist = artist; } public void play() { System.out.println("Playing " + title + " by " + artist); }
}
- 使用XML:
<bean id="compactDisc" class="soundsystem.BlankDisc"> <constructor-arg value="Sgt. Pepper's Lonely Hearts Club Band" /> // argument1 <constructor-arg value="The Beatles" /> // argument2 </bean>
- 使用c-namespace,注意底線後為constructor的argument name
<bean id="compactDisc" class="soundsystem.BlankDisc" c:_title="Sgt. Pepper's Lonely Hearts Club Band" c:_artist="The Beatles" />
- 也可以直接用index表達
<bean id="compactDisc" class="soundsystem.BlankDisc" c:_0="Sgt. Pepper's Lonely Hearts Club Band" c:_1="The Beatles" />
- 若constructor內只有一個argument也可以使用c:_
- wiring collections :c-namespace無法做到的事
- 例如有一個constructor必須傳入collection List
public BlankDisc(String title, String artist, List<String> tracks) { this.title = title; this.artist = artist; this.tracks = tracks; }
- 則此時可以使用XML: <list> tag式<constructor-arg>的sub element,表達內的value會傳到constructor
<bean id="compactDisc" class="soundsystem.BlankDisc"> <constructor-arg value="Sgt. Pepper's Lonely Hearts Club Band" /> <constructor-arg value="The Beatles" /> <constructor-arg> <list> <value>Sgt. Pepper's Lonely Hearts Club Band</value> <value>With a Little Help from My Friends</value> <value>Lucy in the Sky with Diamonds</value> <value>Getting Better</value> <value>Fixing a Hole</value> <!-- ...other tracks omitted for brevity... --> </list> </constructor-arg> </bean>
- 也可以傳入bean ,淡入ref tag,且是set collection
<constructor-arg> <set> <ref bean="sgtPeppers" /> <ref bean="whiteAlbum" /> <ref bean="hardDaysNight" /> <ref bean="revolver" /> ... </set> </constructor-arg>
- c-namespace無法實現wiring collection的功能
- Property injection
- 例:沒有constructor,但在setter有使用到bean
public class CDPlayer implements MediaPlayer { private CompactDisc compactDisc; @Autowired public void setCompactDisc(CompactDisc compactDisc) { this.compactDisc = compactDisc; } public void play() { compactDisc.play(); } }
- 對牆依賴使用constructor injection
- 對可選擇的dependency使用paremeter injection,將其injects至parameter中
<bean id="cdPlayer" class="soundsystem.CDPlayer"> <property name="compactDisc" ref="compactDisc" /> </bean>
- 也可以使用p-namespace
<bean id="cdPlayer" class="soundsystem.CDPlayer" p:compactDisc-ref="compactDisc" />
- compactDisc: parameter name
- 因為c-namespace不能夠使用collection,但可以藉由spring util-namespace
- 步驟:
- 使用util-namespace建立一個list的bean
<util:list id="trackList"> <value>Sgt. Pepper's Lonely Hearts Club Band</value> <value>With a Little Help from My Friends</value> <value>Lucy in the Sky with Diamonds</value> <value>Getting Better</value> <value>Fixing a Hole</value> <!-- ...other tracks omitted for brevity... --> </util:list>
- 將list bean injects至parameter中
<bean id="compactDisc" class="soundsystem.BlankDisc" p:title="Sgt. Pepper's Lonely Hearts Club Band" p:artist="The Beatles" p:tracks-ref="trackList" />
- 其他Spring util-namespace
- util:constant, ref某個type的public static field,並將之轉為bean
- util:list, java.util.List value or ref
- util:map, java.util.Map value or ref
- util:properties, java.util.Properties create java.util.properties type bean
- util:property-path: ref一個bean的property,並將之轉為bean
- util:set: java.util.Set value or ref
沒有留言:
張貼留言