前言
bean
是Spring
最基礎最核心的部分,Spring
簡化代碼主要是依賴於bean
,下面學習Spring
中如何裝配bean
。
裝配bean
Spring
在裝配bean
時非常靈活,其提供了三種方式裝配bean
。
- 在
XML
中進行顯式配置。 - 在
Java
中進行顯式配置。 - 隱式的
bean
發現機制和自動裝配。
自動化裝配bean
自動化裝配技術最為便利,
Spring
從兩個角度實現自動化裝配。
- 組件掃描:
Spring
會自動發現應用上下文中所創建的bean
。 - 自動裝配:
Spring
自動滿足bean
之間的依賴。
自動裝配示例
- pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.hust.grid.leesf.spring</groupId>
<artifactId>spring-learning</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spring.version>3.1.2.RELEASE</spring.version>
<cglib.version>3.1</cglib.version>
<junit.version>4.11</junit.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib-nodep</artifactId>
<version>${cglib.version}</version>
</dependency>
</dependencies>
</project>
- CompactDisc
package ch2;
interface CompactDisc {
void play();
}
其只定義了一個
play
接口,由子類實現。
- SgtPeppers
package ch2;
import org.springframework.stereotype.Component;
@Component
public class SgtPeppers implements CompactDisc {
private String title = "Sgt. Pepper's Lonely Hearts Club Band";
private String artist = "The Beatles";
public void play() {
System.out.println("Playing " + title + " by " + artist);
}
}
SgtPeppers
繼承了CompactDisc
接口,使用Component
注釋為一個Bean
。
- CDPlayerConfig
package ch2;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan("ch2")
public class CDPlayerConfig {
}
配置類,
Spring
會自動加載上下文並掃描ch2
包下的所有bean
。
- CDPlayerTest
package ch2;
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 org.junit.Assert.assertNotNull;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = CDPlayerConfig.class)
public class CDPlayerTest {
@Autowired
private CompactDisc cd;
@Test
public void cdShouldNotNull() {
assertNotNull(cd);
}
}
該類用於測試是否成功裝配
CompactDisc
的bean
,測試成功。
設置Bean名稱
上述示例中
bean
的名稱默認為sgtPeppers
,即將類名的首字母小寫,當然可通過@Component("sp")
設置其名稱為sp
;或者使用@Named("sp")
進行設置。
設置組建掃描基礎包
上述示例中指定掃描
ch2
包,這是通過@ComponentScan("ch")
指定的,當然可以通過@ComponentScan(basePackages="ch2")
進行設置。若設置多個包,則可采用@ComponentScan(basePackages={"ch2","video"})
方式進行設置。除了使用字符串格式表明包名,也可使用類名格式,如@ComponentScan(basePackageClasses = SgtPeppers.class)
指定掃描類。
設置自動裝配
示例中使用
@Autowired
實現自動裝配,Spring
應用上下文中尋找某個匹配的bean
,由於示例中CompactDisc
只有一個聲明為bean
的子類,若有多個聲明為bean
的子類,則會報錯,若沒有子類,也會報錯。@Autowired
注解不僅可以用在屬性上,也可以用在構造函數上,還可以用在Setter方法上。若使用@Autowired(required=false)
時,那么沒有符合的bean
時不會報錯,而是處於未裝配的狀態,要防止空指針情況,其與@Inject
注解功能類似。
- 構造函數使用
@Autowired
注解
@Component
public class CDPlayer implements MediaPlayer {
private CompactDisc cd;
@Autowired
public CDPlayer(CompactDisc cd) {
this.cd = cd;
}
public void play() {
}
}
Setter
方法使用@Autowired
注解
@Autowired
public void setCompactDisc(CompactDisc cd) {
this.cd = cd;
}
在Java中顯式配置
在配置類中顯式配置
bean
,將CDPlayerConfig
中的@ComponentScan("ch2")
移除,此時運行測試用例會報錯,下面通過顯式配置方法來配置bean
。修改CDPlayerConfig
代碼如下。
package ch2;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class CDPlayerConfig {
@Bean
public CompactDisc sgtPeppers() {
return new SgtPeppers();
}
}
上述生成的
bean
名稱與方法名相同,若想設置名稱,可通過@Bean(name=sp)
進行設置。對於如下代碼,調用sgtPeppers
會生成同一個sgtPeppers
的bean
,這是由於sgtPeppers
方法標記為Bean
,Spring
會攔截所有對該方法的調用,並且返回一個已經創建的bean
實例。默認情況下,Spring
中的bean
都是單例的。
@Bean
public CDPlayer cdPlayer() {
return new CDPlayer(sgtPeppers());
}
@Bean
public CDPlayer anotherCDPlayer() {
return new CDPlayer(sgtPeppers());
}
還可以使用如下方法來引用bean
@Bean
public CDPlayer cdPlayer(CompactDisc compactDisc) {
return new CDPlayer(compactDisc);
}
這樣會自動裝配一個CompactDisc
到配置方法中,不用明確使用sgtPeppers
方法來構造CDPlayer
。
通過xml裝配bean
除了使用
JavaConfig
來顯式裝配bean
外,還可以使用xml
文件來裝配bean
。若想在xml
中聲明一個bean
元素,則需要如下操作。
<?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"
xmlns:c="http://www.springframework.org/schema/c"
xmlns:p="http://www.springframework.org/schema/p"
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="sgtPeppers" class="ch2.SgtPeppers" />
</beans>
上述xml
文件中聲明了一個名為sgtPeppers
的bean
,會調用SgtPeppers
的默認構造函數創建bean
。
使用構造器注入初始化bean
使用constructor-arg元素
<bean id="cdPlayer" class="ch2.CDPlayer">
<constructor-arg ref="compactDisc"/>
</bean>
上述代碼表示將ID
為compactDisc
的bean
引用傳遞到CDPlayer
的構造器中。
使用c-命令空間
<bean id="cdPlayer" class="ch2.CDPlayer"
c:cd-ref="compactDisc"/>
</bean>
其中c:
表示命名空間前綴;cd
表示構造器參數名;-ref
表示注入的bean
的引用;compactDisc
表示要注入的bean
的ID
。
將字面量注入到構造器中
<bean id="compactDisc" class="ch2.BlankDisc">
<constructor-arg value="Sgt. Pepper's Lonely Hearts Club Band" />
<constructor-arg value="The Beatles" />
或者使用
<bean id="compactDisc" class="ch2.BlankDisc"
<c:_title="Sgt. Pepper's Lonely Hearts Club Band" />
<c:artist="The Beatles" />
裝配集合到構造器中
裝配字面量到List集合
<bean id="compactDisc" class="ch2.BlankDisc">
<constructor-arg value="Sgt. Pepper's Lonely Hearts Club Band" />
<constructor-arg value="The Beatles" />
<constructor-arg>
<list>
<value>Sgt.AA</value>
<value>Sgt.BB</value>
<value>Sgt.CC</value>
</list>
</constructor-arg>
</bean>
裝配引用List集合
<bean id="compactDisc" class="ch2.BlankDisc">
<constructor-arg value="Sgt. Pepper's Lonely Hearts Club Band" />
<constructor-arg value="The Beatles" />
<constructor-arg>
<list>
<ref bean="sgtPeppers"/>
<ref bean="whiteAlbum"/>
<ref bean="revolver"/>
</list>
</constructor-arg>
</bean>
同理,對於Set
集合只需修改list
為set
即可。
設置屬性
使用xml設置屬性
<bean id="cdPlayer" class="ch2.CDPlayer">
<property name="compactDisc" ref="compactDisc">
</bean>
使用p-命令空間進行裝配
<bean id="cdPlayer" class="ch2.CDPlayer"
p:compactDisc-ref="compactDisc">
</bean>
其組成與c-
類似。
將字面量裝配到屬性中
<bean id="compactDisc" class="ch2.BlankDisc">
<property name="title" value="Sgt. Pepper's Lonely Hearts Club Band" />
<property name="artist"value="The Beatles" />
<property name="tracks">
<list>
<value>Sgt.AA</value>
<value>Sgt.BB</value>
<value>Sgt.CC</value>
</list>
</property>
</bean>
使用p-裝配屬性
<bean id="compactDisc" class="ch2.BlankDisc">
<p:title="Sgt. Pepper's Lonely Hearts Club Band" />
<p:artist="value="The Beatles" />
<property name="tracks">
<list>
<value>Sgt.AA</value>
<value>Sgt.BB</value>
<value>Sgt.CC</value>
</list>
</property>
</bean>
使用util-命名空間裝配集合
<util:list id="tractList">
<value>Sgt.AA</value>
<value>Sgt.BB</value>
<value>Sgt.CC</value>
</util:list>
此時對應修改如下
<bean id="compactDisc" class="ch2.BlankDisc">
<p:title="Sgt. Pepper's Lonely Hearts Club Band" />
<p:artist="value="The Beatles" />
<p:tracks-ref="trackList" />
</bean>
導入和混合配置
在JavaConfig中引用xml配置
將
BlankDisc
從CDPlayerConfig
中剝離出來,放置在自己的配置文件CDConfig
中。此時需要在CDPlayerConfig
中使用@Import(CDConfig.class)
將兩者組合;或者使用更高級別的Config
中使用@Import({CDPlayerConfig.class,CDConfig.class})
組合兩者。若將BlankDisc
配置在cd-config.xml
文件中,則可使用@ImportResource("classpath:cd-config.xml")
導入。
在xml配置中引用JavaConfig
可以使用
import
元素引用配置,如
<import resource="cd-config.xml" />
總結
Spring
有三種方式裝配bean
,使用自動化裝配技術使得代碼更簡潔;並且有多種方式注入屬性。