Spring容器負責創建應用程序中的bean同時通過ID來協調這些對象之間的關系。作為開發人員,我們需要告訴Spring要創建哪些bean並且如何將其裝配到一起。
spring中bean裝配有兩種方式
- 隱式的bean發現機制和自動裝配
- 在java代碼或者XML中進行顯示配置
當然這些方式也可以配合使用。
我們測試代碼如下
CompactDisc和MediaPlayer是兩個接口 其中MediaPlayer的構造方法參數類型為CompactDisc。
我們主要測試CompactDisc和MediaPlayer的實現有沒有注入進來,同時MediaPlayer接口對於CompactDisc的依賴有沒有滿足
package com.zcs; import com.zcs.service.CompactDisc; import com.zcs.service.MediaPlayer; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import static junit.framework.TestCase.assertEquals; import static junit.framework.TestCase.assertNotNull; @RunWith(SpringJUnit4ClassRunner.class) //XML配置 //@ContextConfiguration(locations ="spring-config.xml") //Java代碼配置 @ContextConfiguration(classes =CDPlayerConfig.class) public class CDPlayerTest { @Autowired private CompactDisc cd; @Autowired private MediaPlayer player; @Test public void cdShouldNotBeNull(){ assertNotNull(cd); } @Test public void play(){ assertEquals("Playing 哎呦不錯哦 by 周傑倫",player.play()); } }
1、自動化裝配
Spring從兩個角度來實現自動化裝配:
組件掃描(ComponentScan):自動發現應用上下文中所創建的bean
自動裝配(Autowired):自動滿足bean之間的依賴
CompactDisc接口類和實現類:
public interface CompactDisc { String play(); }
@Component public class SgtPeppers implements CompactDisc { private String title="哎呦不錯哦"; private String artist="周傑倫"; @Override public String play() { return "Playing "+title+" by "+artist; } }
MediaPalyer接口類和實現類
public interface MediaPlayer { String play(); } @Component public class CDPlayer implements MediaPlayer { private CompactDisc cd ; @Autowired public CDPlayer(CompactDisc cd){ this.cd=cd; } @Override public String play(){ return cd.play(); } }
配置類CDPlayerConfig:
@Configuration @ComponentScan public class CDPlayerConfig { }
@ComponentScan作用是掃描帶有@Component注解的類,並為其創建bean。默認是掃描同一包下的類,當然也可以加入參數,指定包名。
如@ComponentScan(basePackages={"com.zcs"})或者@ComponentScan(basePackageClasses={CDPlayer.class,DVDPlayer.class})(即這些類所在的包)
@Autowired滿足自動依賴裝配,可以作用在任何方法上面。
XML形式的自動裝配則修改測試類@ContextConfiguration,改成加載spring-config.xml文件,配置如下:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <bean id="compactDisc" class="com.zcs.impl.SgtPeppers"></bean> <bean id="cdPlayer" class="com.zcs.impl.CDPlayer"> <constructor-arg ref="compactDisc"></constructor-arg> </bean> <context:component-scan base-package="com.zcs"> </beans>
2、顯示bean裝配
當想要將第三方庫中的組件裝配到你的應用中,在這種情況下是沒有辦法在它的類上面添加@Component和@Autowired注解的,因此就不能使用自動化裝配的方案。
只能選擇java代碼或者xml顯示配置
首先可以把兩個實現類上的@Component,還有配置類中的@ComponentScan,CDPlayer類中方法上的@Autowired注解去掉。
這個時候測試應該都通不過。
Java代碼方式:修改CDPlayerConfig配置類為:
@Configuration public class CDPlayerConfig { @Bean public CompactDisc sgtPeppers(){ return new SgtPeppers(); } @Bean public MediaPlayer getCDPlayer(){ return new CDPlayer(sgtPeppers()); }
//@Bean
//public MediaPlayer getCDPlayer(CompactDisc compactDisc){ // return new CDPlayer(compactDisc); //}
}
再運行測試應該會通過了,解釋下 @Bean注解告訴Spring這個方法將會返回一個對象,該對象要注冊為Spring應用上下文中的bean。方法體中包含了最終生成bean實列的邏輯。
第二個方法故意寫的奇怪一點,看起來CompactDisc是通過調用sgtPeppers()方法得到的,但並非如此,Spring會攔截對sgtPeppers方法的調用,轉而從上下文中直接獲取該方法所創建的bean,而不是每次都對其進行實際的調用。
比如:再添加一個方法(測試會通不過)
@Bean public MediaPlayer anotherCDPlayer() { return new CDPlayer(sgtPeppers()); }
這兩個方法依賴注入的CompactDisc將會是同一個bean。
當然通過情況下用注釋的方法更容易理解一點。
XML方式:
首先CDPlayerTest為XML方式,同時修改spring-config.xml配置文件為:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <bean id="compactDisc" class="com.zcs.impl.SgtPeppers"></bean> <bean id="cdPlayer" class="com.zcs.impl.CDPlayer"> <constructor-arg ref="compactDisc"></constructor-arg>
</bean> <context:component-scan base-package="com.zcs"/> </beans>
組件掃描方式的配置不去掉也是沒影響的。
補充:
復雜一點的構造方法
修改SgtPeppers的構造方法
public class SgtPeppers implements CompactDisc { private String title="哎呦不錯哦"; private String artist="周傑倫"; private List<String> tracks=new ArrayList<>(); public SgtPeppers(String title, String artist, List<String> tracks) { this.title = title; this.artist = artist; this.tracks = tracks; } @Override public String play() { return "Playing "+title+" by "+artist; } }
同時修改spring-config.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <bean id="compactDisc" class="com.zcs.impl.SgtPeppers"> <constructor-arg index="0" value="雪狼湖"/> <constructor-arg index="1" value="張學友"/> <constructor-arg index="2"> <list> <value>不老的傳說</value> <value>愛是永恆</value> </list> </constructor-arg> </bean> <bean id="cdPlayer" class="com.zcs.impl.CDPlayer"> <constructor-arg ref="compactDisc"></constructor-arg> </bean> <context:component-scan base-package="com.zcs"/> </beans>
還有屬性注入<property>,c和p命名空間使用就不細說了。對於xml的配置一般在java代碼中也會有對應的配置。但顯示配置用java代碼會類型安全一點
參考:spring實戰第4版