Spring. 自动化装配bean

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_36420790/article/details/82761131

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

  • 组件扫描( component scanning ):Spring会自动发现应用上下文中所创建的 bean。
  • 自动装配( autowiring ):Spring自动满足 bean 之间的依赖

1、创建可被发现的bean

创建一个接口CompactDisc:

package soundsystem;

public interface CompactDisc{
    void play();
}

创建带有@Component注解的CompactDisc接口的一个实现类,这个类会被Spring扫描到并自动创建bean

package soundsystem;

import ...

@Component
public class SgtPeppers implements CompactDisc{
    private String title = "Sgt, Pepper's Lonely Hearts Club Band";
    private String artist = "The Beatles";

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

使用@ComponentScan注解启动组件扫描,@ComponentScan 默认会扫描与配置类相同的包以及其下所有的子包,这样,被@Component注解修饰的类就会被发现

package soundsystem;

import ...

@Configuration
@ComponentScan
public class CDPlayerConfig{

}

也可以使用XML配置的方式来启动组件扫描

<?xml version="1.0" encoding="UTF-8"?>
<beans
    ...
    ...
    >

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

</beans>

2.为组件扫描的 bean 命名

若直接使用 @Component 注解来声明一个 bean,bean 的名字默认为类名首字母小写。

例如,如下 SgtPeppers 类的默认 bean 名称为 sgtPeppers

@Component()
public class SgtPeppers implements CompactDisc{
    ...
}

可以在 @Component 注解中说明此 bean 的名称:

@Component("lonelyHeartClub")
public class SgtPeppers implements CompactDisc{
    ...
}

此外,也可以使用另外一种为 bean 命名的方式:

package soundsystem;
import javax.inject.Named;

@Named("lonelyHeartClub")
public class SgtPeppers implements CompactDisc{
    ...
}

Spring 支持将 @Named 作为 @Component 注解的替代方案,两者之间有一些细微的差异,但在大多数场景下,它们是可以相互替换的。

推荐使用 @Component 注解,因为 @Named 注解并不能清楚的表明它是做什么的


3.设置组件扫描的基础包

在之前的案列中,我们没有为 @ComponentScan 注解设置任何属性,这意味着,按照默认规则,它会以配置类所在包作为基础包( base package )来扫描组件.

有一个原因会促使我们要明确的设置基础包,那就是我们想要将配置类放在单独的包中,使其与其他的应用代码区分开来。

为了指定不同的包,只需要在 @ComponentScan 的 value 属性中指明包的名称:

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

}

或者,如果你想更加明确的表名你所设置的是基础包,那么你可以通过 basePackages 属性进行配置:

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

}

如果你想扫描多个包,只需要将 basePackages 属性的值设置为要扫描包的一个数组即可:

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

}

注意到,basePackages 属性的值是一个 String 类型的数组,这样配置没有问题,但却是不安全的,如果要重构代码的话,这些包的名字可能会被修改,从而导致包扫描出现错误,除了将包设置为简单的 String 类型之外,@ComponentScan 还提供了另一种方法,那就是将其指定为要扫描包中所含的类或接口。

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

}

你可以在包中设置一个专门用来进行包扫描的空标记接口,这样,可以避免对任何实际应用的代码进行重构后,包扫描出现错误。


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

@Component
public class CDPlayer implements MediaPlayer{
    private CompactDisc cd;
    
    @Autowired
    public CDPlayer(CompacrDisc cd){
        this.cd = cd;
    }
    
    public void play(){
        cd.play();
    }
}

以上示例的构造器上添加了 @Autowired 注解,这表明当 Spring 创建 CDPlayer bean 的时候,会通过这个构造器进行实例化并传入一个 CompactDisc 类型的 bean。

@Autowired 注解不仅能够用在构造器上,还可以用在属性设置的 Setter 方法上。

实际上,Setter 方法并没有什么特殊之处,@Autowired 注解可以用在类的任何方法上:如下,@Autowired 注解完全能够发挥作用

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

不管是构造器、Setter 方法还是其他方法,Spring 都会尝试满足方法参数上所声明的依赖,假如有且仅有一个 bean 依赖需求的话,那么这个 bean 就会被装填进来。

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

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

如果有多个 bean 都能满足依赖关系的话,Spring 也将会抛出一个异常,表明没有明确指定要选择那个 bean 进行装配。

处理自动装配的歧义性问题,请参阅我的另一篇文章:Spring. 处理自动装配的歧义性

 

猜你喜欢

转载自blog.csdn.net/qq_36420790/article/details/82761131
今日推荐