Spring实战--自动装配

以前使用过Spring框架,但是始终是学了前面的,忘了后面的,对其中的配置、原理等等也是一头雾水;于是最近开始学习《Spring实战》,然后总结一下每一章的内容(笔记内容可能与书本内容有所出入,另外以下内容基本都会有相应的测试代码);
在学习之前,需要先创建一个maven项目,配置一下Spring相关依赖(这里是Spring 4.7版本)

<dependencies>
        <dependencies>
        <!-- Spring核心依赖 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>4.3.7.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>4.3.7.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>4.3.7.RELEASE</version>
        </dependency>
        <!-- Spring test依赖:方便做单元测试和集成测试 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>4.3.7.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
    </dependencies>

1.Spring配置的可选方案

Spring容器装配Bean有以下三种方案:

  • XML显式配置;
  • 在Java中显式配置;
  • 隐式的bean发现机制和自动装配;

这三种方案都是先声明组件类或bean,再将bean注册到容器中,然后Spring根据容器中各个bean的依赖关系进行装配;
选择配置方案时:

  • 尽量选择自动装配;
  • 如果一定要使用显式配置,最好使用基于Java的配置(Java Config);
  • 除非基于Java的配置无法实现,最后使用XML配置;

2.自动化装配

Spring从两个角度进行自动化装配,将显式配置降低到最少

  • 组件扫描:Spring会自动发现应用上下文中所创建的Bean;
  • 自动装配:Spring自动满足bean之间的依赖;

2.1创建可发现的Bean

以CD为例,CD需要放入CD播放器才有作用,因此可以认为CD对象依赖于CD播放器;
注: 2.1节的类文件均放在同一个包下

首先创建CompactDisc接口,定义CD的概念

//接口定义了CD播放器对CD的操作,将CD播放器的任意实现与CD的耦合降低到了最低
public interface CompactDisc{
    void play();
}

创建一个CompactDisc的实现

@Component
public class SgtPeppers{
    private String title="Sgt.Pepper's Lonely Hearts Club Band";
    private String artist="The Beatles";
    
    public void play(){
        sout("Playing"+title+"by"+artist);
    }
}

分析:
SgtPeppers的内容并不重要,只需关注@Component注解,它表明该类会作为组件类,并告知Spring要为这个类创建bean而无需显式配置它的bean;但是需要注意的是,组件扫描默认不启用,下面需要配置Spring的组件扫描

@Configuration
//@Configuration表明它是一个配置类
@ComponentScan
public class CDPlayerConfig{
    
}

分析:

  • 若未指定包,@ComponentScan默认扫描当前包及其子包下的带@Component注解的类;
  • 若使用XML启用组件扫描,可以使用Spring context命名空间的context:component-scan元素,如下:
<beans>
    <!--base-package指定了查询的包-->
	<context:component-scan base-package="soundsystem.autoconfig"/>
</beans>

组件类和组件扫描都配置好了,下面对功能进行测试,判断CompactDisc是否被创建出来

//测试扫描组件是否能发现CompactDisc
@RunWith(SpringJUnit4ClassRunner.class)
//使用SpringJUnit4ClassRunner.class,测试时自动创建Spring的应用上下文
@ContextConfiguration(classes = CDPlayerConfig.class)
//这一注解表明在CDPlayerConfig中加载配置
public class CDPlayerTest {
    //@Autowired注解将容器中的CompactDisc注入到代码中
    @Autowired
    private CompactDisc cd;

    @Test
    public void cdShouldNotBeNull(){
        assertNotNull(cd);
    }
}

最终结果如下:
测试结果
值得注意的是:
Spring进行测试时,必须使用@RunWith(SpringJUnit4ClassRunner.class)和@ContextConfiguration(classes = CDPlayerConfig.class)注解,功能如注释所言,不然在测试时会出现AssertError异常和空指针异常;
总结:

  • 创建接口和实现类,并对实现类使用@Component注解,表明它是组件类;
  • 创建配置类(记得加上@Configuration表明它是一个配置类),使用@ComponentScan启用组件扫描;至此,创建Bean的工作已经完成;
  • (可忽略) 测试类时需要加上@RunWith(SpringJUnit4ClassRunner.class)和@ContextConfiguration(classes = 配置类类名.class)注解,然后注入容器中的类,使用它的方法;

2.2为组件扫描的bean命名

Spring应用上下文会为所有bean设置一个ID:默认设置为bean的名字,开头字母小写;或者由开发者设置;设置bean的方法如下:

//两种方法均可,我比较推荐方法一
//在编写时,@Named好像不能用,可能是版本问题???希望有大佬指教
//方法一
@Component("lonelyHeartsClub")
public class SgtPeppers implements CompactDisc {
	/*
	具体代码已省略
	*/
}

//方法二
@Named("lonelyHeartsClub")
public class SgtPeppers implements CompactDisc {
	/*
	具体代码已省略
	*/
}

在这里,我使用方法一的代码进行测试:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = CDPlayerConfig.class)
public class SgtPeppersTest {
	//这里为了证明能够从容器中获取重新命名的bean,使用上下文方法获取bean
	//这里是基于CDPlayerConfig类加载Spring上下文
    AnnotationConfigApplicationContext annotationConfigApplicationContext=
            new AnnotationConfigApplicationContext(CDPlayerConfig.class);
    //通过bean的名称获取相关bean
    CompactDisc cd=(SgtPeppers)annotationConfigApplicationContext
    				.getBean("lonelyHeartsClub");


    @Test
    public void testNotNull(){
        assertNotNull(cd);
    }
}

测试结果如下:

2.3设置组件扫描的基础包

@ComponentScan默认扫描当前包,若将配置类放置在单独的包中,就需要设置扫描其他包,方法如下:

//1.扫描单个包
@Configuration
@ComponentScan("soundsystem")
public class CDPlayerConfig {
}

//2.扫描单个包
@Configuration
@ComponentScan(basePackages = "soundsystem")
public class CDPlayerConfig {
}

//3.扫描多个包,类型不安全,重构代码后,指定的包有可能出错
@Configuration
@ComponentScan(basePackages = {"soundsystem","video"})
public class CDPlayerConfig {
}

//4.指定类或接口,这些类所在的包将会作为组件扫描的基础包
@Configuration
@CoponentScan(basePackageClasses = {CDPlayer.class,DVDPlayer.class})
public class CDPlayerConfig {
}

2.4通过为bean添加注解实现自动装配

自动装配是让Spring满足bean依赖的方法,上一节所做的只是组件扫描,但是很多对象只有依赖其他对象才能完成业务,因此需要使用自动装配,将组件和它们的依赖装配在一起;
前面已经提到CD和CDPlayer的依赖,下面创建MediaPlayer接口及CDPlayer类

/**接口MediaPlayer**/
public interface MediaPlayer {
    void play();
}

/**CDPlayer实现接口MediaPlayer**/
@Component
public class CDPlayer implements MediaPlayer{

    private CompactDisc cd;

    @Autowired
    public CDPlayer(CompactDisc cd) {
        this.cd = cd;
    }

    public void play(){
        cd.play();
    }
}

@Autowired表示注入bean,前面已经在容器中注册了CompactDisc的bean,那么这里便会直接注入CompactDisc;(注意:这个类仍需要使用@Component注解)
除了构造器注入参数,还能使用Setter方法甚至普通方法,只要有CompactDisc cd参数,便可以注入

@Component
public class CDPlayer implements MediaPlayer{
	/**...**/
    @Autowired
    public void setCD(CompactDisc cd) {
        this.cd = cd;
    }
    
    /**或者使用更普通的方法**/
    @Autowired
    public void f (CompactDisc cd) {
        this.cd = cd;
    }

    /**...**/
}

注意: 对于@Autowired注解

  • 默认required=true,即注入时,bean必须存在,否则注入失败,报错;
  • reqired=false表示忽略当前要注入的bean,如果有则直接注入,否则跳过,不报错;若代码中没有控制检查,有可能报NullPointerException;
  • 如果存在多个bean满足依赖关系,抛出BeanCreateException;

另外,也可以使用@Named+@Inject替代@Component+@Autowired

@Named
public class CDPlayer implements MediaPlayer{
	/**...**/
    @Inject
    public void setCD(CompactDisc cd) {
        this.cd = cd;
    }
    /**...**/
}

下面验证自动装配

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = CDPlayerConfig.class)
public class CDPlayerTest {
	//SgtPeppers为组件
    @Autowired
    private CompactDisc cd;

    //CDPlayer为组件
    @Autowired
    private MediaPlayer mediaPlayer;

    @Test
    public void play(){
        mediaPlayer.play();
    }
}

测试结果
在这里插入图片描述
测试类中,仅仅声明了CompactDisc 和MediaPlayer并注入,由于MediaPlayer的实现类CDPlayer实现一个注入CompactDisc的方法,在Spring运行时,直接自动装配,因此在测试类的代码层面,两个对象没有任何依赖,却实现了play方法;

2.5总结

自动装配方法的大致流程及注意事项如下:

  • 确定业务逻辑中相互依赖的对象,创建相关接口及其实现类(实现类需要使用@Component注解,表明它是组件类);
  • 创建配置类(使用@Configuration),启用组件扫描(@ComponentScan),@ComponentScan确定需要扫描的包有默认和四种指定名称的方式(直接指定,base-packages指定单个包,base-packages使用数组指定多个包,直接指定一个或多个配置类扫描类所在的包);
  • 在组件类中对方法使用@Autowired注解进行依赖注入;
  • (测试) 加上@RunWith(SpringJUnit4ClassRunner.class)和@ContextConfiguration(classes = 配置类类名.class)对于指定名称的bean,使用AnnotationConfigApplicationContext加载配置类,获取bean,然后就可以测试了;

以上就是Spring自动化装配的流程,下一节将详细讲述Spring通过Java装配bean的流程;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值