Spring容器负责创建应用程序中的bean并通过DI来协调这些对象之间的关系,它提供了三种主要的装配机制:
1、通过XML配置文件装配Bean
通常推荐使用组件扫描和自动装配实现Spring的自动化配置,但当你想要将第三方库中的组件装配到你的应用中时,你没有办法在它的类上添加@Component和@Autowired注解,也就不能使用自动化装配的方案了。
这时,可以采用显式装配方案。有两种可选方案:Java和XML。
本小节介绍如何通过XML配置文件显示装配Bean。
1.1、声明简单的Bean
代码声明了一个简单的bean,通过id属性为bean指定名字,class属性为bean指定类型,要求使用全限定的类名。
当Spring发现这个元素时,将会调用SgtPeppers的默认构造器来创建bean实例。
1.2、借助构造器注入初始化bean
在Spring XML配置中,只有一种声明bean的方式;但XML中声明DI时,有多种可选的配置方案。具体到构造器注入,有两种基本的方案可供选择:
(1)使用 < constructor-arg >元素
当Spring遇到元素时,它会创建一个CDPlayer实例。元素告知Spring要将一个ID为compactDisc的bean引用传递到CDPlayer的构造器中。
(2)使用Spring 3.0所引入的c-命名空间
c-命名空间是在Spring 3.0中引入的,它是在XML中更为简洁地描述构造器参数的方式。 使用前,要在XML的顶部声明其模式。
上图使用了c-命名空间声明构造器参数,它作为元素的一个属性,下图描述了该属性名的组合:
上图的c-命名空间直接引用了构造器参数的名称,会导致在编译代码时,将调试标志(debug symbol)保存在类代码中。如果在优化构建过程中,将调试标志移除掉,那么这种方式可能就无法正常执行了。
替代的方案是我们使用参数在整个参数列表中的位置信息:
对于只有一个构造器参数,可以不用标示参数信息:
1.3、将字面量注入到构造器中
1.3.1、要注入的类
1.3.2、XML之< constructor-arg >注入配置
使用进行构造器参数注入。“ref”属性表示注入其他的bean的引用,“value”属性表示给定的值要以字面量的形式注入到构造器之中。
1.3.3、XML之 c 标签根据参数名称注入字面量
1.3.4、XML之 c 标签根据参数索引注入字面
1.4、装配集合
1.4.1、要装配的类
1.4.2、使用< list >标签进行集合的定义
< list >元素是< constructor-arg >的子元素,表明一个包含多个值的列表将会传递到构造器中,元素用来指定列表中的每元个元素。
与之类似,我们也可以使用< ref >元素替代< value >,实现bean引用列表的装配。例如:
当构造器参数的类型是java.util.List时,应使用< list >元素。但也可按照同样的方式使用< set >。
目前,使用c-命名空间的属性无法实现装配集合的功能。
Spring为< constructor-arg >元素提供了c-命名空间作为替代方案,与之类似,Spring为< property >元素提供了p-命名空间作为替代方案。
1.5、使用p-命名空间进行引用属性装配
1.5.1、p-命名空间装配示例
为了启用p-命名空间,须在XML文件中进行命名空间的声明:
使用p-命名空间,装配compactDisc属性示例:
1.5.2、p-命名空间的属性组成
1.5.3、使用p-命名空间将字面量注入到属性中
要装配的类:
使用p-命名空间装配示例:
与c-命名空间一样,装配bean引用与装配字面量的唯一区别在于是否带有“-ref”后缀。如果没有“-ref”后缀的话,所装配的就是字面量。
注意,我们不能使用p-命名空间来装配集合,但我们可使用Spring util-命名空间中的一些功能来简化BlankDiscbean。
1.5.4、使用util-命名空间进行集合注入
首先,需要在XML中声明util-命名空间及其模式:
使用util-命名空间所提供的功能之一< util:list >元素,创建一个列表的bean:
接下来,我们就可以像使用其他的bean那样,将列表bean注入到BlankDiscbean的tracks属性中:
< util:list >只是util-命名空间中多个元素之一。util-命名空间提供的所有元素如下:
1.6、在JavaConfig中引入XML配置
1.6.1、在XML配置中配置Bean
1.6.2、使用@ImportResource注解引入XML配置
使用@Import和@ImportResource来拆分JavaConfig类。
1.7、在XML配置中引入JavaConfig
< import >元素用于导入其他的XML配置文件,< bean >元素能够导入JavaConfig类。
2、 通过Java代码装配Bean
除了XML配置文件显示装配外,还可以通过JJavaConfig进行显式装配。但JavaConfig是更好的方案,因为它更为强大、类型安全并且对重构友好。
因为JavaConfig是配置代码,这意味着它不应该包含任何业务逻辑,也不应侵入到业务逻辑代码中。所以通常会将JavaConfig放到单独的包中,使它与其他的应用程序逻辑分离开来,避免产生困惑。
本小节介绍如何通过JavaConfig代码显示装配Bean。
2.1、声明简单的Bean
在JavaConfig中声明bean,需要编写一个创建所需类型实例的方法,然后给这个方法添加@Bean注解。@Bean注解会告诉Spring这个方法将会返回一个对象,该对象要注册为Spring应用上下文中的bean。
默认情况下,bean的ID与带有@Bean注解的方法名是一样的。本例中,通过name属性将该bean的ID指定为gtPeppers。
2.2、借助JavaConfig实现注入
2.2.1、引用创建Bean的方法
cdPlayer()方法同样使用了@Bean注解,表明该方法会创建一个bean实例并将其注册到Spring应用上下文中。创建的bean ID为cdPlayer,与方法的名字相同。
cdPlayer()方法中的构造器调用了创建SgtPeppers实例的方法,看似实例CompactDisc是通过调用sgtPeppers()得到的,但因为sgtPeppers()方法上添加了@Bean注解,Spring 会拦截所有对sgtPeppers()的调用,并确保返回的是由Spring本身调用sgtPeppers()方法创建的bean,(默认单例情况下)而不是每次都对其进行实际的调用。
2.2.2、引用Bean的方法创建的实例
cdPlayer()方法请求CompactDisc作为参数。当Spring调用cdPlayer()创建CDPlayer实例时,Spring会自动装配一个CompactDisc到配置方法中。
这种方式引用其他的bean通常是最佳选择。它不要求将CompactDisc声明到同一个配置类中。也没要求CompactDisc必须在JavaConfig中声明。
强调:带有@Bean注解的方法可以采用任何必要的Java功能来产生bean实例。构造器和Setter方法只是@Bean方法的两个简单实例。
3、Bean的自动化装配
Spring从两个角度来实现自动化装配:
-
组件扫描(component scanning):Spring自动扫描应用上下文中创建的bean。
-
自动装配(autowiring):Spring自动满足bean之间的依赖。
Spring自动化装配Bean代码实现:
3.1、定义CD接口类CompactDisc
3.2、定义CompactDisc接口实现类SgtPeppers
@Component注解表明该类为组件类,并告知Spring为这个类创建bean。默认情况下,spring会根据类名自动为Bean创建ID,也可以通过如下两种方式进行Bean实例ID的指定。
方式一:@Component(“lonelyHeartClub”)
方式二:使用Java依赖注入规范(Java Dependency Injection)中所提供的@Named注解来为bean设置ID。使用如下:
Spring的组件扫描默认是不启用的,需要我们显式配置。
3.3、通过Java代码定义Spring组件扫描
@Configuration注解标识此类是Spring配置类。
@ComponentScan注解标识在Spring中启用组件扫描,默认情况下Spring会扫描与配置类相同的包及其子包下带有@Component注解的类。
通过以下方式显示指定@ComponentScan注解扫描范围:
@ComponentScan(basePackages=“soundsystem”):指定单个包;
@ComponentScan(basePackages={“soundsystem”,“video”}):指定多个包;
@ComponentScan(basePackageClasses={CDPlayer.class,DVDPlayer.class}):数组中指定的类或接口所在的包将作为Spring扫描的基础包。
3.4、通过XML配置定义Spring组件扫描
3.5、创建测试类CDPlayerTest测试Bean的自动装配
@RunWith(SpringJUnit4ClassRunner.class)用于自动创建Spring的应用上下文
@ContextConfiguration指明Spring加载配置类的位置(或XML配置文件的位置)
@Autowired注解用于注入Spring容器中创建的Bean对象
3.6、@Autowired注解使用说明
3.6.1、通过构造器自动装配
3.6.2、通过set方法自动装配
其实,对于标注了@Autowired注解的方法,Spring都会尝试满足方法参数上声明的依赖。如果有且只有一个bean匹配依赖,则此bean将会被装配进来;如果没有匹配的bean,Spring在应用上下文创建时会抛出一个异常。为避免异常的出现,可将@Autowired的required属性设置为false,如下图:
将required属性设置为false时,Spring会尝试自动装配,若无匹配bean,Spring将会让这个bean处于未装配状态。
但是,把required属性设置为false后,如果在你的代码中没有null检查,这个处于未装配状态的属性有可能会出现NullPointerException。
对于有多个bean都能满足依赖关系的情况,Spring将会抛出一个异常,表明没有明确指定要选择哪个bean进行自动装配。
7. @Inject注解使用说明
@Autowired是Spring特有的注解。如果你不愿意在代码中到处使用Spring的特定注解来完成自动装配任务的话,可以考虑将其替换为@Inject。如下图:
@Inject注解源于Java依赖注入规范,该规范还为我们定义了@Named注解。在自动装配中,Spring同时支持@Inject和@Autowired。尽管@Inject和@Autowired之间有着一些细微的差别,但是在大多数场景下,它们都是可以互相替换的。