Spring配置的可选方案
Spring容器负责创建应用程序中的bean并通过DI来协调这些对象之间的关系。当描述bean如何进行装配时,Spring具有非常大的灵活性,它提供了三种主要的装配机制:
在XML中进行显式配置
在Java中进行显式配置
隐式的bean发现机制和自动装配
尽可能地使用自动配置的机制。显式配置越少越好。当你必须要显式配置bean的时候(比如,有些源码不是由你来
维护的,而当你需要为这些代码配置bean的时候),推荐使用类型安全并且比XML更加强大的JavaConfig。最后,只有想要使用便利的XML命名空间,并且在JavaConfig中没有同样的实现时,才应该使用XML
自动化装配bean
Spring从两个角度来实现自动化装配:
组件扫描(component scanning):Spring会自动发现应用上下文中所创建的bean
自动装配(autowiring):Spring自动满足bean之间的依赖
组件扫描和自动装配组合在一起就能发挥出强大的威力,它们能够将显式配置降低到最少
创建可被发现的bean
CompactDisc接口在Java中定义了CD的概念
package soundsystem;
public interface CompactDisc
{
void play();
}
CompactDisc的具体内容并不重要,重要的是你将其定义为一个接口。作为接口,它定义了CD播放器对一盘CD所能进行的操作。它将CD播放器的任意实现与CD本身的耦合降低到了最小的程度
带有@Component注解的CompactDisc实现类SgtPeppers
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
@ComponentScan注解启用了组件扫描
以下程序的配置类展现了完成这项任务的最简洁配:
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启用组件扫描
如更倾向于使用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>
测试组件扫描能够发现CompactDisc
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并将其注入到测试代码之中
为组件扫描的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{}
通过为bean添加注解实现自动装配
自动装配就是让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()方法的输出将被发送到控制台上
通过Java代码装配bean
如想将第三方库中的组件装配到你的应用中,在这种情况下无法通过在它的类上添加@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
声明简单的bean
要在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();
}
借助JavaConfig实现注入
前面所声明的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装配bean
创建XML配置规范
在使用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配置文件的根元素
声明一个简单的<bean>
要在基于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配置的合法性
借助构造器注入初始化bean
在Spring XML配置中,只有一种声明bean的方式:使用<bean>元素并指定class属性。Spring会从这里获取必要的信息来创建bean。但是,在XML中声明DI时,会有多种可选的配置方案和风格。具体到构造器注入,有两种基本的配置方案可供选择:
<constructor-arg>元素
使用Spring 3.0所引入的c-命名空间
构造器注入bean引用
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" />
将字面量(literal value)注入到构造器中
迄今为止,所做的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-命名空间实现构造器注入时,它们之间还有一些细微的差别
设置属性
使用Spring XML实现属性注入
设属性注入的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,其中包含值或引用 |
导入和混合配置
在JavaConfig中引用XML配置
现在假设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
{
}
在XML配置中引用JavaConfig
在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>
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。