在spring中面哥,對(duì)象無(wú)需自己查找或創(chuàng)建與其所關(guān)聯(lián)的其他對(duì)象,容器負(fù)責(zé)把需要相互協(xié)作的對(duì)象引用賦予各個(gè)對(duì)象,容器的這種創(chuàng)建對(duì)象之間協(xié)作關(guān)系的行為被稱(chēng)為裝配作媚,也被成為依賴(lài)注入(DI),依賴(lài)注入有3種方案可供選用帅刊,如下
1纸泡、在XML中進(jìn)行顯式的配置
2、在Java中進(jìn)行顯式的配置
3赖瞒、隱式的bean發(fā)現(xiàn)機(jī)制和自動(dòng)裝配
隱式的bean發(fā)現(xiàn)機(jī)制和自動(dòng)裝配
看下面一個(gè)實(shí)例
1女揭、創(chuàng)建一個(gè)接口
public interface CompactDisc {
void play();
}
2蚤假、添加這個(gè)接口的實(shí)現(xiàn),注意我們?cè)陬?lèi)的頭部添加了@Component的注解,表明這個(gè)類(lèi)是一個(gè)組件
@Component
public class SgtPeppers implements CompactDisc {
private String title = "Sgt. Pepper's Lonely Hearts Club Band";
private String artist = "The Beatles";
@Override
public void play() {
System.out.println("Playing " + title + " by " + artist);
}
}
3吧兔、添加對(duì)這個(gè)組件的配置磷仰,這個(gè)類(lèi)里面什么東西都沒(méi)有,只有類(lèi)的頭部有兩個(gè)注解境蔼,分別為@Configuration和@ComponentScan灶平,其中@ComponentScan注解表明會(huì)對(duì)這個(gè)包中的包含@Component的類(lèi)進(jìn)行掃描
@Configuration
@ComponentScan
public class CDPlayConfig {
}
4阎姥、編寫(xiě)一個(gè)簡(jiǎn)單的JUnit例子
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = CDPlayConfig.class)
public class CDPlayConfigTest {
@Autowired
private CompactDisc cd;
@Test
public void cdShouldNotBeNull(){
assertNotNull(cd);
}
}
在上面的JUnit的例子中绎狭,類(lèi)的頭部包含了@RunWith注解和@ContextConfiguration注解,其中RunWith中的SpringJUnit4ClassRunner.class將會(huì)為我們創(chuàng)建Spring應(yīng)用的上下文眉抬,ContextConfiguration中的classes = CDPlayConfig.class則表明我們將在CDPlayConfig中加載配置
運(yùn)行吴藻,會(huì)發(fā)現(xiàn)JUnit的測(cè)試是通過(guò)的
為被裝配的組件命名
Spring應(yīng)用的上下文中的所有的bean都會(huì)有一個(gè)ID來(lái)標(biāo)識(shí)自己瞒爬,假如我們不強(qiáng)制指定,那么Spring會(huì)根據(jù)類(lèi)名為其指定一個(gè)ID调缨,一般會(huì)把類(lèi)的第一個(gè)字母小寫(xiě)來(lái)作為ID疮鲫,比如上面的SgtPeppers
,那么這個(gè)bean的ID就是sgtPeppers
,我們也可以自己指定ID弦叶,有兩種方式俊犯,分別如下
第一種是在Component里面直接寫(xiě)上ID
@Component("lonelyHeartClub")
public class SgtPeppers implements CompactDisc {
...
}
第二種是使用DI的參數(shù)@Named注解,如下
@Named("lonelyHeartClub")
public class SgtPeppers implements CompactDisc {
...
}
不過(guò)推薦使用第一種
對(duì)于@ComponentScan的注解伤哺,假如我們不指定掃描的包燕侠,那么就會(huì)掃描配置類(lèi)當(dāng)前所在的包,我們也可以指定我們需要進(jìn)行掃描的包立莉,如下
@ComponentScan(basePackages = "com.fan.soundsystem")
public class CDPlayConfig {
}
不過(guò)也可以使用類(lèi)所在包作為掃描的包绢彤,如下
@Configuration
@ComponentScan(basePackageClasses = CDPlayConfig.class)
public class CDPlayConfig {
}
@Autowired是自動(dòng)裝配注解,表明會(huì)在上下文中搜索bean并裝配到參數(shù)之中蜓耻,假如沒(méi)有匹配的bean茫舶,那么就會(huì)拋出異常,為了避免異常的發(fā)生刹淌,我們可以設(shè)置@Autowired的required屬性為false饶氏。我們同樣可以使用@Inject來(lái)替代@Autowired,如下
@Inject
public void setCompactDisc(CompactDisc cd){
this.cd = cd;
}
通過(guò)JavaConfig進(jìn)行bean的裝配
1有勾、我們針對(duì)CompactDisc創(chuàng)建一個(gè)新的實(shí)現(xiàn)
@Component
public class Revolver implements CompactDisc {
private String title = "Revolver";
private String artist = "The Beatles";
@Override
public void play() {
System.out.println("Playing " + title + " by " + artist);
}
}
2疹启、然后我們把CDPlayConfig 中的@ComponentScan注解移除,并添加我們自己寫(xiě)的注入,需要注意的是蔼卡,假如我們有兩個(gè)創(chuàng)建CompactDisc 的方法被增加了注解@bean喊崖,那么我們將得不到一個(gè)正確的結(jié)果,如下面注釋的部分不能出現(xiàn)
@Configuration
public class CDPlayerConfig1 {
// @Bean
// public CompactDisc sgtCompactDisc(){
// return new SgtPeppers();
// }
@Bean
public CompactDisc randomBeatlesCD(){
int choice = (int) Math.floor(Math.random() * 4);
if(choice == 0){
return new SgtPeppers();
}else {
return new Revolver();
}
}
@Bean
public CDPlayer cdPlayer(){
return new CDPlayer(randomBeatlesCD());
}
}
3、對(duì)JUnit的實(shí)例做一下簡(jiǎn)單的修改
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = CDPlayerConfig1.class)
public class CDPlayConfigTest {
// @Rule
// public final StandardOutputStreamLog log = new
@Autowired
private CDPlayer cd;
@Test
public void cdShouldNotBeNull(){
assertNotNull(cd.getCompactDisc());
}
這樣同樣能夠取得相同的效果
通過(guò)XML進(jìn)行bean的裝配
基于XML裝配bean的方法配置風(fēng)格有兩種,分別為
<constructor-arg>元素
使用Spring3.0所引入的c空間
使用<constructor-arg>的配置文件如下所示
<?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">
<bean id="compactDisc" class="com.fan.soundsystem.SgtPeppers"/>
<bean id="cdPlayer" class="com.fan.soundsystem.CDPlayer">
<constructor-arg ref="compactDisc"/>
</bean>
</beans>
我們可以通過(guò)這種方式來(lái)獲取bean
使用c命名空間的方式配置如下
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:c="http://www.springframework.org/schema/c"
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">
<bean id="compactDisc" class="com.fan.soundsystem.SgtPeppers"/>
<bean id="cdPlayer" class="com.fan.soundsystem.CDPlayer" c:cd-ref="compactDisc"/>
</beans>
我們?yōu)樯厦娴呐渲镁帉?xiě)一個(gè)測(cè)試方法荤懂,如下
public class Main {
public static void main(String[] args){
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("springConfig.xml");
CDPlayer cd = context.getBean(CDPlayer.class);
cd.getCompactDisc().play();
context.close();
}
}
c命名空間相比之下更加的靈活
我們有時(shí)候需要將字面量注入到bean之中茁裙,我們?cè)谶@種情況下該怎么做呢?
如下势誊,我們先創(chuàng)建一個(gè)類(lèi)呜达,并不設(shè)置任何注解
public class BlankDisc implements CompactDisc {
private String title;
private String artist;
private List<String> tracks;
public BlankDisc(String title,String artist,List<String> tracks){
this.title = title;
this.artist = artist;
this.tracks = tracks;
}
@Override
public void play() {
System.out.println("Playing " + title + " by " + artist);
for(String track : tracks)
System.out.println("-Track:" + track);
}
}
然后利用配置給這個(gè)bean進(jìn)行配置
<bean id="blankDisc" class="com.fan.soundsystem.BlankDisc">
<constructor-arg value="Sgt. Pepper's Lonely Hearts Clubs Band"/>
<constructor-arg value="The Beatles"/>
<constructor-arg>
<list>
<value>Sgt. Peper's Lonely Hearts Club Band</value>
<value>Fixing a Hole</value>
</list>
</constructor-arg>
</bean>
和引用注入一樣谣蠢,我們同樣可以使用c命名空間進(jìn)行注入粟耻,如下
<bean id="blankDisc" class="com.fan.soundsystem.BlankDisc"
c:title="Sgt. Pepper's Hearts Club Band"
c:artist="The Beatles"
c:tracks-ref="trackList"/>
以上都是構(gòu)造器注入的方法,有時(shí)候我們需要對(duì)屬性進(jìn)行注入眉踱,那么我們可以使用下面這種方式挤忙,首先我們需要改造一下BlankDisc的寫(xiě)法
public class BlankDisc implements CompactDisc {
private String title;
private String artist;
private List<String> tracks;
// public BlankDisc(String title,String artist,List<String> tracks){
// this.title = title;
// this.artist = artist;
// this.tracks = tracks;
// }
public void setTitle(String title){this.title = title;}
public void setArtist(String artist){this.artist = artist;}
public void setTracks(List<String> tracks){this.tracks = tracks;}
@Override
public void play() {
System.out.println("Playing " + title + " by " + artist);
for(String track : tracks)
System.out.println("-Track:" + track);
}
}
注意其中的構(gòu)造器必須注釋掉,否則會(huì)出錯(cuò)谈喳,然后我們對(duì)配置文件進(jìn)行編寫(xiě)
<bean id="blankDisc" class="com.fan.soundsystem.BlankDisc">
<property name="title" value="Sgt. Pepper's Lonely Hearts Club Band"/>
<property name="artist" value="The Beatles"/>
<property name="tracks">
<list>
<value>Getting Better</value>
<value>Fixing a Hole</value>
</list>
</property>
</bean>
同樣册烈,我們還可以使用p空間進(jìn)行配置,看下面
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:c="http://www.springframework.org/schema/c"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:p="http://www.springframework.org/schema/p"
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/util
http://www.springframework.org/schema/util/spring-util.xsd">
<bean id="compactDisc" class="com.fan.soundsystem.SgtPeppers"/>
<util:list id="trackList">
<value>Getting Better</value>
<value>Fixing a Hole</value>
</util:list>
<bean id="blankDisc" class="com.fan.soundsystem.BlankDisc"
p:title="Sgt. Pepper's Lonely Hearts Club Band"
p:artist="The Beatles"
p:tracks-ref="trackList"/>
</beans>
混合配置
在通常的使用中婿禽,我們不僅可以使用上面3中方式的任何一種赏僧,而且我們還可以將各種方式進(jìn)行組合使用,常見(jiàn)的做法是在JavaConfig中引用XML和在XML中引用JavaConfig扭倾,那么我們應(yīng)該怎么做才能達(dá)到這一點(diǎn)呢
JavaConfig中引用XML
假如我們?cè)谝粋€(gè)測(cè)試單元中同事使用CDPlayer和BlankDisc淀零,那么我們可以對(duì)CDPlayerConfig1 增加對(duì)BlankDisc的配置,如下所示
@Configuration
@ImportResource("classpath:springConfig.xml")
public class CDPlayerConfig1 {
// @Bean
// public CompactDisc sgtCompactDisc(){
// return new SgtPeppers();
// }
@Bean
public CompactDisc randomBeatlesCD(){
int choice = (int) Math.floor(Math.random() * 4);
if(choice == 0){
return new SgtPeppers();
}else {
return new Revolver();
}
}
@Bean
public CDPlayer cdPlayer(){
return new CDPlayer(randomBeatlesCD());
}
}
我們?cè)傩薷囊幌聹y(cè)試單元的代碼膛壹,如下
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = CDPlayerConfig1.class)
public class CDPlayConfigTest {
// @Rule
// public final StandardOutputStreamLog log = new
@Autowired
private CDPlayer cd;
@Autowired
private BlankDisc bd;
@Test
public void cdShouldNotBeNull(){
assertNotNull(cd.getCompactDisc());
assertNotNull(bd);
}
}
運(yùn)行并查看運(yùn)行的結(jié)果驾中,如下所示
XML中引用JavaConfig
我們先創(chuàng)建一個(gè)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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<import resource="springConfig.xml"/>
<bean class="com.fan.soundsystem.CDPlayerConfig1"/>
</beans>
再編寫(xiě)測(cè)試文件模聋,如下
public static void main(String[] args){
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("TotalConfig.xml");
AnnotationConfigApplicationContext context1 = new AnnotationConfigApplicationContext(CDPlayerConfig1.class);
BlankDisc bd = context.getBean(BlankDisc.class);
CDPlayer cdPlayer1 = context1.getBean(CDPlayer.class);
// CDPlayer cdPlayer = context1.getBean(CDPlayer.class);
cdPlayer1.play();
bd.play();
context.close();
}
運(yùn)行并查看結(jié)果