自动装配 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