Spring对bean的装配机制(一)——隐式自动装配

来源:互联网 发布:如何下载网站的源码 编辑:程序博客网 时间:2024/04/27 10:33

Spring容器负责创建应用程序中的bean并通过DI来协调这些对象之间的关系,那Spring装配bean时是如何装配的呢?

Spring非常灵活,它提供了三种主要的装配机制:

1.隐式的bean发现机制和自动装配。

2.在xml中进行显式装配。

3.在Java中进行显式装配。


本文对第一种机制进行详细说明:

一.自动装配bean

   spring从两个角度来实现自动化装配:

     *.组件扫描(component scanning):Spring会自动发现应用上下文中所创建的bean.

     *.自动装配(autowiring):Spring自动满足bean之间的依赖.

 说明:自动装配bean有两种方式,一种是java代码直接注解的形式,一种是xml配置的形式。xml配置的形式是目前国内大部分公司在用的,java代码直接注解的用的不多,不过个人觉得比xml的形式方便很多。


     (一)java形式的自动装配

                1.创建一个CompactDisc接口

package soundsystem;/** *@作者:JackHisen(gwd) *@email:1154978352@qq.com *@时间:2017年7月29日 下午7:20:50 *@version 1.0  */public interface CompactDisc {void play();}

                 2.创建CompactDisc接口的实现类

/** *@作者:JackHisen(gwd) *@email:1154978352@qq.com *@时间:2017年7月29日 下午7:21:38 *@version 1.0  */@Component//@Component("sgtPeppers")可以通过这样的方式来给bean设置idpublic class SgtPeppers implements CompactDisc {private String title="Sgt.Pepper's Lonely Hearts Club Band";private String artist="The Beatles";public void play() {// TODO Auto-generated method stubSystem.out.println("Playing"+title+"by"+artist);}}

SgtPeppers的具体内容并不重要,你需要注意的是SgtPeppers类上的@Component注解。这个简单的注解表名该类会作为组件类,并告知Spring要为这个类创建bean。没有必要显式配置SgtPeppers bean,因为这个类使用了@Component注解,所以Spring会为你把事情处理妥当。

不过,组件扫描默认是不启用的,所以我们还需要显式配置一下Spring,从而命令它去寻找带有@Component注解的类,并为其创建bean。CDPlayerConfig类展示了完成这项任务最简洁的配置。

注:还有另外一种bean命名的方式,这种方式不使用@Component注解,而是使用Java依赖注入规范中所提供的@Named注解来为bean设置ID。Spring支持将@Named作为@Component注解的替代方案。两者之间有些细微的差异,但是在大多数场景中,他们它们是可以相互替换的。


             3.开启组件扫描

package soundsystem;import org.springframework.context.annotation.ComponentScan;import org.springframework.context.annotation.Configuration;/** *@作者:JackHisen(gwd) *@email:1154978352@qq.com *@时间:2017年7月29日 下午7:24:49 *@version 1.0  */@Configuration@ComponentScanpublic class CDPlayerConfig {}

类CDPlayerConfig通过java代码定义了Spring的装配规则,它并没有显式地声明任何bean,不过使用了@ComponentScan注解,这个注解能够在Spring中启用组件扫描。

如果没有配置的话,@ComponentScan默认会扫描与配置类相同的包。因为CDPlayerConfig类位于soundsystem包中,因此Spring将会默认扫描这个包以及这个包下的所有子包,查找带有@Component注解的类。这样的话就能发现CompactDisc,并且会在Spring中自动为其创建一个bean。

@Configuration表名这个类是一个配置类,该类应该包含在Spring应用上下文中如何创建bean的细节。


注:@ComponentScan注解如果想要扫描其他包可以添加value值,如果想扫描多个基础包可以用用basePackages属性进行配置

@Configuration@ComponentScan(value="soundsystem")public class CDPlayerConfig {}


@Configuration@ComponentScan(basePackages={"soundsystem","otherpackage"})public class CDPlayerConfig {}

上面这个例子中,所设置的基础包是以 String类型表示的,这是可以的,但是这种方法是类型不安全的。如果你重构代码的话,那么所指定的基础包就可能会出错。

除了将包设置成String类型之外,@ComponentScan还提供了另外一种方法,那就是将其指定为包中所含的类或接口:

@Configuration@ComponentScan(basePackageClasses={CompactDisc.class,otherExist.class})public class CDPlayerConfig {}


                   4.编写测试类

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;/** *@作者:JackHisen(gwd) *@email:1154978352@qq.com *@时间:2017年7月29日 下午7:33:48 *@version 1.0  */@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration(classes=CDPlayerConfig.class)public class CDPlayerTest {@Autowiredprivate CompactDisc compactDisc;@Testpublic void cdShoudNotBeNull(){assertNotNull(compactDisc);}}
CDPlayerTest使用了Spring的SpringJunit4ClassRunner,以便在测试开始的时候自动创建Spring的应用上下文。注解@ContextConfiguration会告诉它需要在CDPlayerConfig中加载配置。因为CDPlayerConfig类包含了@ComponentScan,因此最终的应用上下文应该包含CompactDisc bean。


扩展:

在上面的应用程序中,所有的对象都是独立的,彼此之间没有任何依赖,就行SgtPeppers bean这样,那么那你所需要的可能就是组件扫描而已。但是,很多对象会依赖其他的对象才能完成任务。这样的话,我们就需要一种方法能够将组件扫描得到的bean和它们的依赖装配在一起,这个时候就需要用到Spring的自动装配了。

简单来说,自动装配就是让Spring自动满足bean依赖的一种方法,在满足依赖的过程中,会在Spring应用上下文中寻找匹配某个bean需求的其他bean。为了声明要进行自动装配,我们可以借助Spring的@Autowired注解(或者@Inject注解)。

(1)创建有依赖的类

例如下面的CDPlayer类,它的构造器上添加了@Autowired注解,这表明当Spring创建CDPlayer bean的时候,会通过这个构造器来进行实例化并且会传入一个可设置给CompactDisc类型的bean。

package soundsystem;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Component;/** *@作者:JackHisen(gwd) *@email:1154978352@qq.com *@时间:2017年7月30日 下午9:09:43 *@version 1.0  */@Componentpublic class CDPlayer implements MediaPlayer{private CompactDisc cd;//当Spring创建CDPlayer bean的时候,会通过这个构造器来进行实例化并且会传入一个可设置给CompactDisc类型的bean//@Auto注解不仅能够用在构造器上还能用在类的任何地方@Autowired public CDPlayer(CompactDisc cd) {this.cd = cd;}public void play(){cd.play();}}
需要注意的是,@Autowired注解可以在类的任何地方。另外如果没有匹配的bean,那么在应用的上下文创建的时候,Spring会抛出一个异常。为了避免异常的出现,你可以将@Autowired的required属性设置为false,这个时候Spring会尝试执行自动装配,但是如果没有装配的bean的话,SPring将会让bean处于未装配的状态。但是,把ruquired属性设置为false时,你需要谨慎对待。如果在你的代码中没有进行null检查的话,这个处于未装配状态的属性有可能会出现NullPointerException。


    (2)测试自动装配

package soundsystem;import static org.junit.Assert.*;import org.apache.tomcat.util.security.MD5Encoder;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;/** *@作者:JackHisen(gwd) *@email:1154978352@qq.com *@时间:2017年7月29日 下午7:33:48 *@version 1.0  */@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration(classes=CDPlayerConfig.class)public class CDPlayerTest {@Autowiredprivate CompactDisc compactDisc;@Autowiredprivate MediaPlayer player;@Testpublic void cdShoudNotBeNull(){assertNotNull(compactDisc);}@Testpublic void play(){player.play();}}


      (二)xml形式的自动装配

      1.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:aop="http://www.springframework.org/schema/aop"xmlns:tx="http://www.springframework.org/schema/tx" xmlns:jdbc="http://www.springframework.org/schema/jdbc"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="     http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd     http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd     http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.0.xsd     http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd     http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"><context:component-scan base-package="soundsystem"/>     </beans>

     2.测试类

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;/** *@作者:JackHisen(gwd) *@email:1154978352@qq.com *@时间:2017年7月29日 下午7:33:48 *@version 1.0  */@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration(locations="classpath:applicationContext.xml")public class CDPlayerTest {@Autowiredprivate CompactDisc compactDisc;@Testpublic void cdShoudNotBeNull(){assertNotNull(compactDisc);}}
其他均与java代码形式一致。