Spring容器负责建立应用程序中的bean并经过DI来协调这些对象之间的关系。当描述bean如何进行装配时,Spring具备很是大的灵活性,它提供了三种主要的装配机制:html
在XML中进行显式配置java
在Java中进行显式配置git
隐式的bean发现机制和自动装配github
尽量地使用自动配置的机制。显式配置越少越好。当你必需要显式配置bean的时候(好比,有些源码不是由你来
维护的,而当你须要为这些代码配置bean的时候),推荐使用类型安全而且比XML更增强大的JavaConfig。最后,只有想要使用便利的XML命名空间,而且在JavaConfig中没有一样的实现时,才应该使用XMLspring
Spring从两个角度来实现自动化装配:数组
组件扫描(component scanning):Spring会自动发现应用上下文中所建立的bean安全
自动装配(autowiring):Spring自动知足bean之间的依赖ide
组件扫描和自动装配组合在一块儿就能发挥出强大的威力,它们可以将显式配置下降到最少测试
package soundsystem; public interface CompactDisc { void play(); }
CompactDisc的具体内容并不重要,重要的是你将其定义为一个接口。做为接口,它定义了CD播放器对一盘CD所能进行的操做。它将CD播放器的任意实现与CD自己的耦合下降到了最小的程度优化
package soundsystem; 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类上使用了@Component注解。这个简单的注解代表SgtPeppers类会做为组件类,并告知Spring要为这个类建立bean。没有必要显式配置SgtPeppersbean,由于这个类使用了@Component注解,因此Spring会为你把事情处理稳当
不过,组件扫描默认是不启用的。咱们还须要显式配置一下Spring,从而命令它去寻找带有@Component注解的类,并为其建立bean
如下程序的配置类展示了完成这项任务的最简洁配:
package soundsystem; import org.springframework.context.annotation.componentScan; import org.springframework.context.annotation.Con; @Component @ComponentScan public class CDPlayerConfig{}
类CDPlayerConfig经过Java代码定义了Spring的装配规则。观察可知,CDPlayerConfig类并无显式地声明任何bean,只不过它使用了@ComponentScan注解,这个注解可以在Spring中启用组件扫描
若是没有其余配置的话,@ComponentScan默认会扫描与配置类相同的包。由于CDPlayerConfig类位于soundsystem包中,所以Spring将会扫描这个包以及这个包下的全部子包,查找带有@Component注解的类。这样的话,就能发现CompactDisc,而且会在Spring中自动为其建立一个bean
如更倾向于使用XML来启用组件扫描的话,那么可使用Spring context命名空间的<context:component-scan>元素。如下程序展现了启用组件扫描的最简洁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/comtext" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/beans/context http://www.springframework.org/schema/beans/context/spring-context.xsd"> <context:component-scan base-package="soundsystem"/> </beans>
package soundsystem; import static org.junit.Assert.*; 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; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes=CDPlayerConfig.class) public class CDPlayerTest { @Autowired private CompactDisc cd; @test_139772[test] public void cdShouldNotBeNull() { assertNotNull(cd); } }
CDPlayerTest使用了Spring的SpringJUnit4ClassRunner,以便在测试开始的时候自动建立Spring的应用上下文。注解@ContextConfiguration会告诉它须要在CDPlayerConfig中加载配置。由于CDPlayerConfig类中包含了@ComponentScan,所以最终的应用上下文中应该包含CompactDiscbean
在测试代码中有一个CompactDisc类型的属性,而且这个属性带有@Autowired注解,以便于将CompactDiscbean
注入到测试代码之中。最后,会有一个简单的测试方法断言cd属性不为null。若是它不为null的话,就意味着Spring可以发现CompactDisc类,自动在Spring上下文中将其建立为bean并将其注入到测试代码之中
Spring应用上下文中全部的bean都会给定一个ID。前面的例子中,尽管没有明确地为SgtPeppersbean设置ID,但Spring会根据类名为其指定一个ID。具体来说,这个bean所给定的ID为sgtPeppers,也就是将类名的第一个字母变为小写
若想为这个bean设置不一样的ID,则需将指望的ID做为值传递给@Component注解:
@Component("lonelyHeartsClub") public class SgtPeppers implements CompactDisc { ... }
另一种为bean命名的方式,使用Java依赖注入规范(Java Dependency Injection)中所提供的@Named注解来为bean设置ID:
package soundsystem; import javax.inject.Named; @Named("lonelyHeartsClub") public class SgtPeppers implements CompactDisc { ... }
为了指定不一样的基础包,所须要在@ComponentScan的value属性中指明包的名称:
@Configuration @ComponentScan("soundsystem") public class CDPlayerConfig{}
若需更加清晰地代表你所设置的是基础包,经过basePackages属性进行配置:
@Configuration @ComponentScan(basePackages = "soundsystem") public class CDPlayerConfig{}
若是须要能够设置多个基础包,只须要将basePackages属性设置为要扫描包的一个数组便可:
@Configuration @ComponentScan(basePackages = {"soundsystem", “videos”}) public class CDPlayerConfig{}
上面例子中,所设置的基础包是以String类型表示的。这是可行的,但这种方法是类型不安全(not type-safe)的。如进行代码重构,那么所指定的基础包可能会出现错误
除了将包设置为简单的String类型以外,@ComponentScan提供的另一种方法,将其指定为包中所包含的类或接口:
@Configuration @ComponentScan(basePackageClasses = {CDPlayer.class, DVDPlayer.class}) public class CDPlayerConfig{}
自动装配就是让Spring自动知足bean依赖的一种方法,在知足依赖的过程当中,会在Spring应用上下文中寻找匹配某个bean需求的其余bean。为了声明要进行自动装配,咱们能够借助Spring的@Autowired注解
下述程序CDPlayer类。它的构造器上添加了@Autowired注解,这代表当Spring建立CDPlayerbean的时候,会经过这个构造器来进行实例化而且会传入一个可设置给CompactDisc类型的bean
经过自动装配,将一个CompactDisc注入到CDPlayer之中:
package soundsystem; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @Component public class CDPlayer implement MediaPlayer { private CompactDisc cd; @Autowired public CDPlayer(CompactDisc cd) { this.cd = cd; } public void play { cd.play(); } }
@Autowired注解不只可以用在构造器上,还能用在属性的Setter方法上。好比说,若是CDPlayer有一个setCompactDisc()方法,那么能够采用以下的注解形式进行自动装配:
@Autowired public void setCompactDisc(CompactDisc cd)
@Autowired注解能够用在类的任何方法上。假设CDPlayer类有一个insertDisc()方法,那么@Autowired可以像在setCompactDisc()上那样,发挥彻底相同的做用:
@Autowired public void insertDisc(CompactDisc cd) { this.cd = cd; }
无论是构造器、Setter方法仍是其余的方法,Spring都会尝试知足方法参数上所声明的依赖。假若有且只有一个bean匹配依赖需求的话,那么这个bean将会被装配进来
若是没有匹配的bean,那么在应用上下文建立的时候,Spring会抛出一个异常。为了不异常的出现,你能够将@Autowired的required属性设置为false:
@Autowired public CDPlayer(CompactDisc cd) { this.cd = cd; }
将required属性设置为false时,Spring会尝试执行自动装配,若没有匹配的bean,Spring将会让这个bean处于未装配的状态。但把required属性设置为false时,须要谨慎对待。若是代码中没有进行null检查,处于未装配状态的属性可能出现NullPointerException
@Autowired是Spring特有的注解。若是不肯代码中处处使用
Spring的特定注解来完成自动装配任务,可考虑替换为@Inject:
package soundsystem; import javax.inject.Inject; import javax.inject.Named; @Named public class CDPlayer { ... @Inject public CDPlayer(CompactDisc cd) { this.cd = cd; } ... }
@Inject注解来源于Java依赖注入规范,该规范同时还定义了@Named注解。在自动装配中,Spring同时支持@Inject和
@Autowired。尽管@Inject和@Autowired之间有着一些细微的差异,可是在大多数场景下,是能够互相替换的
除了注入CompactDisc,还将CDPlayerbean注入到测试代码的player成员变量之中(它是更为通用的MediaPlayer类型)。在play()测试方法中,咱们能够调用CDPlayer的play()方法,并断言它的行为与预期一致
在测试代码中使用System.out.println()。所以,该样例中使用了StandardOutputStreamLog,是来源于System Rules库(http://stefanbirkner.github.i...)的一个JUnit规则,该规则可以基于控制台的输出编写断言。SgtPeppers.play()方法的输出将被发送到控制台上
如想将第三方库中的组件装配到你的应用中,在这种状况下没法经过在它的类上添加@Component和@Autowired注解的方法实现自动化装配
JavaConfig与其余的Java代码存在区别,在概念上,它与应用程序中的业务逻辑和领域代码不一样的。尽管都使用相同的语言进行表述,但JavaConfig是配置代码。这意味着它不该该包含任何业务逻辑,JavaConfig也不该该侵入到业务逻辑代码之中。尽管不是必须的,但一般会将JavaConfig放到单独的包中,使它与其余的应用程序逻辑分离开来,这样对于它的意图就不会产生困惑了
建立JavaConfig类的关键在于为其添加@Configuration注解,@Configuration注解代表这个类是一个配置类,该类应该包含在Spring应用上下文中如何建立bean的细节
package soundsystem; import org.springframework.context.annotation.Configuration; @Configuration public class CDPlayerConfig { ... }
到此为止,都是依赖组件扫描来发现Spring应该建立的bean。尽管能够同时使用组件扫描和显式配置,但在本节更加关注于显式配置,所以将CDPlayerConfig的@ComponentScan注解移除掉了。移除了@ComponentScan注解,此时的CDPlayerConfig类就没有任何做用了。如如今运行CDPlayerTest,测试失败,并出现BeanCreation-Exception异常。测试指望被注入CDPlayer和CompactDisc,但这些bean根本就没有建立,由于组件扫描不会发现它们。下一节,将展示如何使用JavaConfig装配CDPlayer和CompactDisc
要在JavaConfig中声明bean,需编写一个建立所需类型实例的方法,而后给这个方法添加@Bean注解。以下代码声明了CompactDisc bean:
@Bean public CompactDisc sgtPeppers() { return new SgtPeppers(); }
@Bean注解会告诉Spring这个方法将会返回一个对象,该对象要注册为Spring应用上下文中的bean。方法体中包含了最终产生bean实例的逻辑
默认状况下,bean的ID与带有@Bean注解的方法名是同样的。在本例中,bean的名字将会是sgtPeppers。若是你想为其设置成一个不一样的名字的话,那么能够重命名该方法,也能够经过name属性指定一个不一样的名字:
@Bean(name= "lonelyHeartsClubBand") public CompactDisc sgtPeppers() { return new SgtPeppers(); }
前面所声明的CompactDisc bean很是简单,自身没有其余依赖。如今,须要声明依赖于CompactDisc的CDPlayer bean。在JavaConfig中装配bean的最简单方式就是引用建立bean的方法。以下就是一种声明CDPlayer的可行方案:
@Bean public CDPlayer cdPlayer() { return new CDPlayer(sgtPeppers()); }
这个方法会建立一个bean实例并将其注册到Spring应用上下文中。所建立的bean ID为cdPlayer,与方法的名字相同。cdPlayer()的方法体与sgtPeppers()稍微有些区别。在这里并无使用默认的构造器构建实例,而是调用了须要传入CompactDisc对象的构造器来建立CDPlayer实例。看起来,CompactDisc是经过调用sgtPeppers()获得的,但状况并不是彻底如此。由于sgtPeppers()方法上添加了@Bean注解,Spring将会拦截全部对它的调用,并确保直接返回该方法所建立的bean,而不是每次都对其进行实际的调用
@Bean public CDPlayer cdPlayer() { return new CDPlayer(sgtPeppers()); } @Bean public CDPlayer anotherCDPlayer() { return new CDPlayer(sgtPeppers()); }
默认状况下,Spring中的bean都是单例的,并不必为第二个CDPlayer bean建立彻底相同的SgtPeppers实例。因此,Spring会拦截对sgtPeppers()的调用并确保返回的是Spring所建立的bean,也就是Spring自己在调用sgtPeppers()时所建立的CompactDiscbean。所以,两个CDPlayer bean会获得相同的SgtPeppers实例
@Bean public CDPlayer cdPlayer(CompactDisc compactDisc) { return new CDPlayer(sgtPeppers()); }
在这里,cdPlayer()方法请求一个CompactDisc做为参数。当Spring调用cdPlayer()建立CDPlayerbean的时候,它会自动装配一个CompactDisc到配置方法之中。而后,方法体就能够按照合适的方式来使用它。借助这种技术,cdPlayer()方法也可以将CompactDisc注入到CDPlayer的构造器中,并且不用明确引用CompactDisc的@Bean方法
经过这种方式引用其余的bean一般是最佳的选择,由于它不会要求将CompactDisc声明到同一个配置类之中。在这里甚至没有要求CompactDisc必需要在JavaConfig中声明,实际上它能够经过组件扫描功能自动发现或者经过XML来进行配置
能够将配置分散到多个配置类、XML文件以及自动扫描和装配bean之中,只要功能完整健全便可。无论CompactDisc是采用什么方式建立出来的,Spring都会将其传入到配置方法中,并用来建立CDPlayer bean
在使用XML为Spring装配bean以前,你须要建立一个新的配置规范。在使用JavaConfig的时候,这意味着要建立一个带有@Configuration注解的类,而在XML配置中,这意味着要建立一个XML文件,而且要以<beans>元素为根
<?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/beans/context"> <!-- configuration details go here --> </beans>
如上基本的XML配置已比同等功能的JavaConfig类复杂。在JavaConfig中只须要@Configuration,但在XML中,须要在配置文件的顶部声明多个XML模式(XSD)文件,这些文件定义了配置Spring的XML元素
借助Spring Tool Suite建立XML配置文件建立和管理Spring XML配置文件的一种简便方式是使用Spring Tool Suite(https://spring.io/tools/sts)。在Spring Tool Suite的菜单中,选择File>New>Spring Bean Configuration File,可以建立Spring XML配置文件,而且能够选择可用的配置命名空间
用来装配bean的最基本的XML元素包含在spring-beans模式之中,在上面这个XML文件中,它被定义为根命名空间。<beans>是该模式中的一个元素,它是全部Spring配置文件的根元素
要在基于XML的Spring配置中声明一个bean,咱们要使用springbeans模式中的另一个元素:<bean>。<bean>元素相似于JavaConfig中的@Bean注解。能够以下的方式声明CompactDiscbean:
<bean class="soundsystem.SgtPeppers" />
这里声明了一个简单的bean,建立这个bean的类经过class属性来指定的,而且要使用全限定的类名
因没明确给定ID,因此这个bean将会根据全限定类名来进行命名。在本例中,bean的ID将会是“soundsystem.SgtPeppers#0”。其中,“#0”是一个计数的形式,用来区分相同类型的其余bean。若是你声明了另一个SgtPeppers,而且没有明确进行标识,那么它自动获得的ID将会是“soundsystem.SgtPeppers#1”
一般来说,更好的办法是借助id属性,为每一个bean设置一个你本身选择的名字:
<bean id = "compactDisc" class="soundsystem.SgtPeppers" />
减小繁琐为了减小XML中繁琐的配置,只对那些须要按名字引用的bean(好比,你须要将对它的引用注入到另一个bean中)进行明确地命名
借助IDE检查XML的合法性使用可以感知Spring功能的IDE,如Spring Tool Suite,可以在很大程度上帮助你确保Spring XML配置的合法性
在Spring XML配置中,只有一种声明bean的方式:使用<bean>元素并指定class属性。Spring会从这里获取必要的信息来建立bean。可是,在XML中声明DI时,会有多种可选的配置方案和风格。具体到构造器注入,有两种基本的配置方案可供选择:
<constructor-arg>元素
使用Spring 3.0所引入的c-命名空间
1.<constructor-arg>元素方案:
现已声明SgtPeppers bean,而且SgtPeppers类实现了CompactDisc接口,因此实际上已经一个能够注入到CDPlayerbean中的bean。所需作的是在XML中声明CDPlayer并经过ID引用SgtPeppers:
<bean id="cdplayer" class="soundsystem.CDPlayer"> <constructor-arg ref="compactDisc" /> </bean>
当Spring遇到这个<bean>元素时,会建立一个CDPlayer实例。<constructor-arg>元素会告知Spring要将一个ID
为compactDisc的bean引用传递到CDPlayer的构造器中
2.c-命名空间方案:
c-命名空间是在XML中更为简洁地描述构造器参数的方式。要使用它的话,必需要在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:c="http://www.springframework.org/schema/c" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="bar" class="x.y.Bar"/> <bean id="baz" class="x.y.Baz"/> <!-- 标准XML格式 --> <bean id="foo" class="x.y.Foo"> <constructor-arg name="bar" ref="bar"/> <constructor-arg name="baz" ref="baz"/> <constructor-arg name="email" value="foo@bar.com"/> </bean> <!-- c命名空间格式 --> <bean id="foo" class="x.y.Foo" c:bar-ref="bar" c:baz-ref="baz" c:email="foo@bar.com"/> <!-- 还可使用c命名空间的参数索引格式 --> <bean id="foo" class="x.y.Foo" c:_0-ref="bar" c:_1-ref="baz" c:_2="foo@bar.com"/> </beans>
在c-命名空间和模式声明以后,就可使用它来声明构造器参数了,以下所示:
<bean id="cdplayer" class="soundsystem.CDPlayer" c:cd-ref="compactDisc" />
属性名以“c:”开头,也就是命名空间的前缀。接下来就是要装配的构造器参数名,在此以后是“-ref”,这是一个命名的约定,它会告诉Spring,正在装配的是一个bean的引用,这个bean的名字是compactDisc,而不是字面量“compactDisc”
引用参数的名称有些怪异,由于须要编译代码时,将调试标志(debug symbol)保存在类代码中。若是优化构建过程,将调试标志移除掉,那么这种方式可能就没法正常执行。根本不用去标示参数的方案:
<bean id="cdplayer" class="soundsystem.CDPlayer" c:_-ref="compactDisc" />
迄今为止,所作的DI一般指的都是类型的装配——也就是将对象的引用装配到依赖于它们的其余对象之中——而有时须要的只是用一个字面量值来配置对象
1.<constructor-arg>元素方案:
package soundsystem; public class BlankDisc implements CompactDisc { private String title; private String artist; public BlankDisc(String title, String artist) { this.title = title; this.artist = artist; } public void play() { System.out.println("Playing" + title + "by" + artist); } }
<bean id="compactDisc" class="soundsystem.BlankDisc"> <constructor-arg value = "Sgt. Pepper's Lonely Hearts Club Band" /> <constructor-arg value = "The Beatles" /> </bean>
上述程序使用<constructor-arg>元素进行构造器参数的注入。没有使用“ref”属性来引用其余的bean,而使用了
value属性,经过该属性代表给定的值要以字面量的形式注入到构造器之中
2.c-命名空间方案:
引用构造器参数名:
<bean id="compactDisc" class="soundsystem.BlankDisc" c:_title="Sgt. Pepper's Lonely Hearts Club Band" c:_artist="The Beatles" />
经过参数索引装配相同的字面量值:
<bean id="compactDisc" class="soundsystem.BlankDisc" c:_0="Sgt. Pepper's Lonely Hearts Club Band" c:_1="The Beatles" />
含有磁道列表概念的BLankDisc
package soundsystem.collections; import java.ytil.List; import soundsystem.CompactDisc; 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 play() { System.out.println("Playing" + title + "by" + artist); for(String track : tracks) { System.out.println("-Track: " + track); } } }
这个变动会对Spring如何配置bean产生影响,在声明bean时,必需要提供一个磁道列表。较好的解决方法是提供一个磁道名称的列表。首先,可使用<list>元素将其声明为一个列表:
<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 Friend</value> <value>Lucy in the Sky with Diamonds</value> <value>Getting Better</value> <value>Fixing a Hole</value> <!-- ...other tracks omiitted for brevity... -> </list> </constructor-arg> </bean>
其中,<list>元素是<constructor-arg>的子元素,这代表一个包含值的列表将会传递到构造器中。其中,<value>元素用来指定列表中的每一个元素
也可以使用<ref>元素替代<value>,实现bean引用列表的装配。假设有一个Discography类,构造器以下所示:
public Discography(String artist, List<CompactDisc> cds) { ... }
采起以下的方式配置Discography bean:
<bean id="beatlesDiscography" class="soundsystem.Discography"> <constructor-arg value = "The Beatles" /> <constructor-arg> <list> <ref bean="SgtPeppers" /> <ref bean="whiteAlbum" /> <ref bean="hardDaysNight" /> <ref bean="revolver" /> ... </list> </constructor-arg> </bean>
在装配集合方面,<constructor-arg>比c-命名空间的属性更有优点。目前,使用c-命名空间的属性没法实现装配集合的功能。使用<constructor-arg>和c-命名空间实现构造器注入时,它们之间还有一些细微的差异
设属性注入的CDPlayer以下所示:
package soundsystem; import org.springframework.beans.factory.annotation.Autowired; import soundsystem.CompactDisc; import soundsystem.MediaPlayer; public class CDPlayer implement MediaPlayer { private CompactDisc compactDisc; @Autowired public CDPlayer(CompactDisc compactDisc) { this.compactDisc = compactDisc; } public void play { compactDisc.play(); } }
做为一个通用的规则,强依赖使用构造器注入,而对可选性的依赖使用属性注入
p-命名空间:
<?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:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- 标准XML格式 --> <bean name="john-classic" class="com.example.Person"> <property name="name" value="John Doe"/> <property name="spouse" ref="jane"/> </bean> <!-- p命名空间格式 --> <bean name="john-modern" class="com.example.Person" p:name="John Doe" p:spouse-ref="jane"/> </beans>
使用p-命名空间装配compactDisc属性:
<bean id = "cdplayer" class = "soundsystem.CDPlayer" p:compactDisc-ref = "compactDisc" />
属性的名字使用了“p:”前缀,代表咱们所设置的是一个属性。接下来就是要注入的属性名。最后,属性的名称以“-ref”结尾,这会提示Spring要进行装配的是引用,而不是字面量
如下BlankDisc彻底经过属性注入进行配置,而不是构造器注入。新的BlankDisc类以下所示:
package soundsystem.collections; import java.ytil.List; import soundsystem.CompactDisc; public class BlankDisc implements CompactDisc { private String title; private String artist; private List<String> tracks; public setTitle(String title) { this.title = title; } public setArtistString artist) { this.artist = artist; } public setTracks(List<String> tracks) { this.tracks = tracks; } public void play() { System.out.println("Playing" + title + "by" + artist); for(String track : tracks) { System.out.println("-Track: " + track); } } }
借助<property>元素的value属性装配这些属性,内嵌<list>元素设置tracks属性:
<bean id="compactDisc" class="soundsystem.BlankDisc"> <property name = "title" value = "Sgt. Pepper's Lonely Hearts Club Band" /> <property name = "artist" value = "The Beatles" /> <property name = "tracks"> <list> <value>Sgt. Pepper's Lonely Hearts Club Band</value> <value>With a Little Help from My Friend</value> <value>Lucy in the Sky with Diamonds</value> <value>Getting Better</value> <value>Fixing a Hole</value> <!-- ...other tracks omiitted for brevity... -> </list> </property> </bean>
使用p-命名空间:
<bean id = "compactDisc" class="soundsystem.BlankDisc" p:title = "Sgt. Pepper's Lonely Hearts Club Band" p:artist = "The Beatles"> <property name = "tracks"> <list> <value>Sgt. Pepper's Lonely Hearts Club Band</value> <value>With a Little Help from My Friend</value> <value>Lucy in the Sky with Diamonds</value> <value>Getting Better</value> <value>Fixing a Hole</value> <!-- ...other tracks omiitted for brevity... -> </list> </property> </bean>
与c-命名空间同样,装配bean引用与装配字面量的惟一区别在因而否带有“-ref”后缀。若是没有“-ref”后缀的话,所装配的就是字面量
不能使用p-命名空间来装配集合,没有便利的方式使用p-命名空间来指定一个值(或bean引用)的列表。但可使用Spring util-命名空间中的一些功能来简化BlankDiscbean
首先,须要在XML中声明util-命名空间及其模式:
<?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:p="http://www.springframework.org/schema/p" xmlns:util="http://http://www.springframework.org/schema/util" 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"> ... </beans>
util-命名空间所提供的功能之一就是<util:list>元素,它会建立一个列表的bean。<util:list>可将磁道列表转移到BlankDisc bean以外,并将其声明到单独的bean之中,以下所示:
<util:list id = "trackList"> <value>Sgt. Pepper's Lonely Hearts Club Band</value> <value>With a Little Help from My Friend</value> <value>Lucy in the Sky with Diamonds</value> <value>Getting Better</value> <value>Fixing a Hole</value> <!-- ...other tracks omiitted for brevity... -> </util:list>
将磁道列表bean注入到BLANkDisc bean的tracks属性中:
<bean id = "compactDisc" class = "soundsystem.BlankDisc" p:title = "Sgt. Pepper's Lonely Hearts Club Band" p:artist = "The Beatles" p:tracks-ref = "trackList" />
元素 | 描述 |
---|---|
<util:constant> | 引用某个类型的public static域,并将其暴露为bean |
<util:list> | 建立一个java.util.List类型的bean,其中包含值或引用 |
<util:map> | 建立一个java.util.Map类型的bean,其中包含值或引用 |
<util:properties> | 建立一个java.util.properties类型的bean |
<util:property-path> | 引用一个bean的属性(或内嵌属性),并将其暴露为bean |
<util:set> | 建立一个java.util.Set类型的bean,其中包含值或引用 |
如今假设CDPlayerConfig已经有些笨重,所以将其进行拆分。虽然目前只定义了两个bean,远远称不上复杂Spring配置。不过,在此假设两个bean已经算多了。一种方案是将BlankDisc从CDPlayerConfig拆分出来,定义到它本身的CDConfig类中,以下所示:
package soundsystem; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class CDConfig { @Bean public CompactDisc compactDisc() { return new SgtPeppers(); } }
上述程序的compactDisc()方法已经从CDPlayerConfig中移除掉了,现须要将这两个类组合在一块儿。一种方法就是
在CDPlayerConfig中使用@Import注解导入CDConfig:
package soundsystem; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; @Configuration @Import(CDConfig.class) public class CDPlayerConfig { @Bean public CDPlayer cdPlayer(CompactDisc compactDisc) { return new CDPlayer(compactDisc); } }
更好的办法,不在CDPlayerConfig中使用@Import,而是建立一个更高级别的SoundSystemConfig,在
这个类中使用@Import将两个配置类组合在一块儿:
package soundsystem; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; @Configuration @Import(CDConfig.class) public class CDPlayerConfig { @Bean public CDPlayer cdPlayer(CompactDisc compactDisc) { return new CDPlayer(compactDisc); } }
更好的办法,不在CDPlayerConfig中使用@Import,而是建立一个更高级别的SoundSystemConfig,在这个类中使用@Import将两个配置类组合在一块儿:
package soundsystem; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; @Configuration @Import({CDPlayerConfig.class, CDConfig.class}) public class SoundSystemConfig { }
现已将CDPlayer的配置与BlankDisc的配置分开,假设(基于某些缘由)但愿经过XML来配置BlankDisc,以下所示:
<bean id="compactDisc" class="soundsystem.BlankDisc"> <c:_0 = "Sgt. Pepper's Lonely Hearts Club Band" /> <c:_1 = "The Beatles" /> <constructor-arg> <list> <value>Sgt. Pepper's Lonely Hearts Club Band</value> <value>With a Little Help from My Friend</value> <value>Lucy in the Sky with Diamonds</value> <value>Getting Better</value> <value>Fixing a Hole</value> <!-- ...other tracks omiitted for brevity... -> </list> </constructor-arg> </bean>
使用@ImportResource注解同时加载XML配置和其余基于Java的配置,假设BlankDisc定义在名为cdconfig.
xml的文件中,该文件位于根类路径下,那么能够修改SoundSystemConfig,让它使用@ImportResource注解,以下所示:
package soundsystem; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; @Configuration @Import(CDPlayerConfig.class) @ImportResource("classpath:cd-config.xml") public class SoundSystemConfig { }
在JavaConfig配置中,使用@Import和@ImportResource来拆分JavaConfig类。在XML中,使用import元素来拆分XML配置
设但愿将BlankDisc bean拆分到本身的配置文件中,该文件名为cd-config.xml,这与以前使用@ImportResource是同样的。课在XML配置文件中使用<import>元素来引用该文件:
<?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:c="http://www.springframework.org/schema/c" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <import resoune = "cd-config.xml"/> <bean id = "cdPlayer" class = "soundsystem.CDPlayer" c:cd-ref = "compactDisc"/> </beans>