自动装配 bean

作者: 禅与发现的乐趣 | 来源:发表于2018-06-30 18:23 被阅读1次

创建可被发现的 Bean

CD 需要注入到 CD 播放器中进行播放,这样 CD 播放器才能正常运行。

CD 接口类
package soundsystem;

public interface CompactDisc {

    void play();
}
CD接口的一个实现
package soundsystem;

import org.springframework.stereotype.Component;

@Component
public class SgtPepper implements CompactDisc {

    private String title = "Sgt. Pepper's Loney Herts Club Band";
    private String artist = "The Beatles";

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

这个 CD 的实现类使用了@Component注解,这个注解表明该类会作为组件类,并告知 Spring 要为这个类创建 Bean。

组件扫描

前面 CD 的实现类添加了注解,会作为一个组件类,但是组件扫描默认是不开启的,我们需要显式地配置一下 Spring,从而命令它去寻找带有@Component注解的类,并为其创建 bean。

package soundsystem;

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

@Configuration
@ComponentScan
public class CDPlayerConfig {
}

注解@ComponentScan能够在 Spring 中启用组件扫描,如果没有其它配置的话,@ComponentScan默认会扫描与配置类相同的包,Spring 会扫描这个包以及这个包下的所有子包,查找带有@Component注解的类。

为组件扫描的 bean 命名

Spring 应用上下文中所有的 bean 都会给定一个 ID,前面虽然我们没有明确地为 SgtPeppers bean 指定 ID,但是 Spring 会根据类名为其指定一个 ID,默认将类名的第一个字母变为小写,也就是sgtPeppers

如果要为 bean 设置不同的 ID,可以将ID 作为值传给@Component注解。

@Component("loneyHeartClub")
public class SgtPepper implements CompactDisc {
   ...
}

设置组件扫描的基础包

前面的代码中,我们没有为@ComponentScan设置任何属性,所以它会以配置类所在包作为基础包来扫描组件。但是如果我们想将配置类放在单独的包中,使其与其它应用代码区分开来,那默认的就不行了。

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

或者显式地指定 basePackages:

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

可以同时指定多个基础包:

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

上面的基础包的指定都是以字符串的形式,但是这种方法是类型不安全的,如果你重构代码的话,可能就会出现错误。除了将包设置为简单的字符串类型外,@ComponentScan还提供了另外一种方法,那就是将其指定为包中所包含的类或接口:

@Configuration
@ComponentScan(basePackageClasses = { SgtPepper.class, DVDPlayer.class})
public class CDPlayerConfig {
}

上面指定的类有些是组件类,为了更好区分,可以在这些包中创建一个空的扫描标记接口,然后使用这个接口类指定扫描包。

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

自动装配就是让 Spring 自动满足 bean 依赖的一种方法,在这个过程中,会在 Spring 应用上下文中寻找某个 bean 需求的其它bean。为了声明要进行自动装配,可以使用@Autowired注解。

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

@Component
public class CDPlayer implements MediaPlayer {

    private CompactDisc cd;

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

    @Override
    public void play() {
    }
}

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

@Autowired不仅可以用在构造器上,实际上它可以用在任何方法上。

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

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

Spring 在尝试满足方法参数上所声明的依赖时,如果有且只有一个 bean(也就是一个实现)能匹配依赖需求的话,那么这个 bean 将会被包装进来。

如果没有匹配的 bean,那么在应用上下文创建的时候,Spring 会抛出一个异常,为了避免这个异常,你可以设置属性 required 为 false:

@Autowired(required = false)
public void insertDisc(CompactDisc cd) {
    this.cd = cd;
}

默认是为 true 的,当设置为 false 的时候,在代码要记得在使用时判空。

如果有多个备案都满足依赖关系的话,Spring 会抛出一个异常,这表明没有明确指定要选择哪个 bean 进行装配。后面会讲自动装配中的歧义性。

Java 依赖注入规范里面的@Inject@Autowired是同样的作用,大部分情况下可以互用。

相关文章

网友评论

    本文标题:自动装配 bean

    本文链接:https://www.haomeiwen.com/subject/bnfxuftx.html