Spring 如何使用自动化装配 bean?

Spring 提供了三种主要的装配机制

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

Q:应该选择哪一种装配机制?
A:以上三种配置方案,可以随意选择。但是笔者建议,尽可能地使用自动配置的机制,显示配置越少越好。
另外,当你必须要显示的配置 bean 的时候(比如,有些源码不是由你来维护的,而当你需要为这些代码配置 bean 的时候),我推荐使用类型安全并且比 XML 更加强大的 JavaConfig
当你想要使用便利的 XML 命名空间,并且在 JavaConfig 中没有同样的实现时,才应该使用 XML。


2.2 自动化装配 bean

Q:Spring 如何实现自动化装配?

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

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

A:以下给出简化的代码:
CompactDisc.java

package soundsystem;

/**
 *  作为接口,定义了 CD 播放器对一盘 CD 所能进行的操作
 */
public interface CompactDisc {
    void play();
}

SgtPeppers.java

package soundsystem;

import org.springframework.stereotype.Component;

/**
 * @Component 表明了该类会作为组件类,并告知 Spring 要为这个类创建 bean
 * 不过,组件扫描默认是不启用的。我们需要显式配置一下 Spring,从而命令它去寻找带有 @Component 注解的类,并为其创建bean。
 */
@Component
public class SgtPeppers implements CompactDisc {

    private String title = "title";
    private String artist = "attist";

    public void play() {
        System.out.println("Playing "+title+" by "+artist);
    }
}

CDPlayerConfig.java 通过 Java 启动组件扫描

package soundsystem;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

/**
 * @ComponentScan 注解启用了组件扫描
 * 如果没有其他配置的话,默认会扫描与配置类相同的包以及该包下的所有子包,查找带有 @Component 注解的类。
 * 注意:默认情况下,一定要将类放在包下面,否则会出错。
 */
@Configuration
@ComponentScan
public class CDPlayerConfig {
}

或者通过 XML 启用组件扫描 spring-config.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/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <context:component-scan base-package="soundsystem"/>

</beans>

测试组件扫描能够发现 CompactDisc。
CDPlayerTest.java

package soundsystem;

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;

import static org.junit.Assert.assertNotNull;

/**
 * 测试组件扫描能够发现 CompactDisc
 *
 * 使用了 Spring 的 SpringJUnit4ClassRunner,以便在测试开始的时候自动创建 Spring 的应用上下文。
 *
 * @ContextConfiguration 会告诉它需要在 CDPlayerConfig 中加载配置。
 * 因为 CDPlayerConfig 类中包含了 @ComponentScan,因此最终的应用上下文应该包含了 CompactDiscbean
 *
 */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes= CDPlayerConfig.class)
public class CDPlayerTest {

    @Autowired
    private CompactDisc compactDisc;

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

注意:笔者采用的是基于 Gradle 创建的项目,测试时,需要导入 spring-test 包。
Gradle 库地址:http://mvnrepository.com/
build.gradle文件

dependencies {
    compile 'org.springframework:spring-context:5.0.0.RC2'
    testCompile group: 'org.springframework', name: 'spring-test', version: '5.0.0.RC2'
}
Q:怎么为组件扫描的 bean 命名?

A:如代码所示。
SgtPeppers.java

/**
 * 前面例子没有明确的为 SgtPeppersbean 设置 ID,默认ID为 sgtPeppers
 * 此处明确的为 SgtPeppersbean 设置 ID 为"lonelyHeartsClub"。
 * 也可以用 @Named("lonelyHeartsClub") 来替代,但是不建议使用。
 */
@Component("lonelyHeartsClub")
public class SgtPeppers implements CompactDisc {...}
Q:怎么设置组件扫描的基础包?

A:代码如下。

/**
 * @ComponentScan 注解启用了组件扫描
 * 默认为配置类所在的包作为基础包来扫描组件。
 * 也可以像下面一样指定不同的基础包。
 */
@Configuration
@ComponentScan("soundsystem")
//@ComponentScan(basePackages = "soundsystem")
//设置多个基础包
//@ComponentScan(basePackages = {"soundsystem","video"})
//将其指定为包中所包含的类或接口
@ComponentScan(basePackageClasses = {CDPlayer.class,DVDPlayer.class})
public class CDPlayerConfig {
}
Q:怎么实现自动装配?

需要一种能够将扫描得到的 bean 和它们的依赖装配在一起。
A:我们可以通过 Spring 的 @Autowired 注解来实现。代码如下:

package soundsystem;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * 通过自动装配,将一个 CompactDisc 注入到 CDPlayer 之中
 */
@Component
public class CDPlayer {

    private CompactDisc compactDisc;

    /**
     * @Autowired 注解,表明当 Spring 创建 CDPlayerbean 的时候,
     * 会通过这个构造器来进行实例化并且会传入一个可设置给 CompactDisc 类型的 bean。
     * 不管是用在构造器、setter 方法还是其他的方法上,Spring 都会满足方法参数上所声明的依赖。
     */
    @Autowired(required = false)
    public CDPlayer(CompactDisc compactDisc) {
        this.compactDisc = compactDisc;
    }

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

假如有且只有一个 bean 匹配依赖需要的话,那么这个 bean 将会被装配起来。
如果没有匹配的bean,那么在应用上下文创建的时候,Spring 会抛出一个异常。为了避免异常的出现,你可以将 @Autowired 的 required 属性设置为 false

    /**
     * ①、如果没有匹配的 bean 的话,Spring 将会让这个 bean 处于未装配的状态。
     *     需要注意,如果代码中没有进行 null 检查的话,可能会出现 NullPointerException 异常。
     * ②、如果有多个 bean 都能满足依赖关系的话,Spring 将会抛一个异常,表明没有明确指定选择哪个bean 进行自动装配。
     */
    @Autowired(required = false)
    public CDPlayer(CompactDisc compactDisc) {
        this.compactDisc = compactDisc;
    }

@Autowired 是 Spring 特有的注解。当然你也可以将其替换为 @Inject 注解(来源于 Java 依赖注入规范)。@Inject 和 @Autowired 之间有细微差异,但是大部分场景下,它们可以互相替换

上一篇:Spring 的新功能
下一篇:Spring 如何通过 Java 代码装配 bean ?

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值