美文网首页
Spring学习(四)-- IoC 容器高级用法

Spring学习(四)-- IoC 容器高级用法

作者: MikeShine | 来源:发表于2021-10-19 11:45 被阅读0次

1. 写在前面

在之前的笔记中,我们对IoC容器的核心问题--ROC & DI 进行了学习。
下面我们看一下 IoC 容器的一些高级用法:

  • 定制 Bean
  • 使用 资源文件 Resource
  • 注入 配置
  • 使用 条件配置

2. 定制 Bean

2.1 @Scope

这个注解会让每次我们使用容器实例去 getBean() 时,得到一个新的Bean 实例 ,原型 (prototype)。
否则在一次容器创建到销毁过程中,对于特定的 Bean 都会返回同一个实例,单例 (singleton)。

@Component
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class MailService{

}

2.2 注入 List

在注入的时候,除了可以注入一个对象之外,我们还可以注入一个 List

public Interface Validator{
    Boolean validate(String name);
}

其有多个实现类

// 两个不同的实现类
@Component
public class ValidatorOne implements Validator{
   Boolean validate(String name){
        if(name.equals("mike")){
               return true;
        }
  }
}

@Component
public class ValidatorTwo implements Validator{
   Boolean validate(String name){
        if(name.equals("Shine")){
               return true;
        }
  }
}

之后进行验证

@Component
public class ValidatingShit{
      @Autowired
      List<Validator> validatingList;

      public void validateShit(String name){
          for (Validator validator : this.validatingList){
               validator.validate(name);
          }
      }    
}

注入 List 支持,所有的类型为 Validator 的 Bean 装进来,List 中元素是有顺序的,因此可以通过 @Order 注解来规定顺序

@Component
@Order(1)
public class ValidatorOne implements Validator{}

@Component
@Order(2)
public class ValidatorTwo implements Validator{}

2.3 可选注入 reqiured=false

没有规定可选注入,则容器找不到这个注入对象,就会抛出NoSuchBeanDefinitionException异常。
指定可选注入后,就会忽略。

@Component
public class MailService {
    @Autowired(required = false)
    ZoneId zoneId = ZoneId.systemDefault();
    ...
}

非常适合有定义就是用定义,没有定义就使用默认的情况。
比如上面,如果有ZoneId的Bean,就注入,没有就算了。

2.4 @Bean创建第三方 Bean

如果一个 Bean 不在我们的 package 内,可以通过 @Bean 注在@Configuration 类中创建

@Configuration 
@ComponentScan
public class AppConfig{
    // 创建一个Bean:
    @Bean
    ZoneId createZoneId() {
        return ZoneId.of("Z");
    }
}

2.5 初始化@PostConstruct和销毁@preDestroy

主要针对两种情况:

  • 注入之后需要初始化(执行监听)的Bean;
  • 关闭容器之前需要释放资源(连接池)的Bean

引入依赖:

<dependency>
    <groupId>javax.annotation</groupId>
    <artifactId>javax.annotation-api</artifactId>
    <version>1.3.2</version>
</dependency>

加入相关的注解

@Component
public class MailService{
    @Autowired(required=false)
    User user;
    
    @PostConstruct
    void init(){
    sout("This is the post construct shit");
    }
     
    @PreDestroy
    void end(){
    sout("This is the destroy shit before shutdown the IoC");
    }

}

2.6 @Qualifier 使用别名

如果出现多个同名的 Bean,在注入时就会出现问题。这时候使用 @Qualifier 注解来规定Bean的别名,注入时候也使用 @Qualifier 来指明别名。
也可以使用 @Primary 注解来指定默认注入的Bean,非显式指定名称时,导入该primaryBean。

@Configuration
@ComponentScan
public class AppConfig {
    @Bean
    ZoneId createZoneOfZ() {
        return ZoneId.of("Z");
    }

    @Bean
    ZoneId createZoneOfUTC8() {
        return ZoneId.of("UTC+08:00");
    }
}
@Component
public class MailService {
    @Autowired(required = false)
    @Qualifier("z") // 指定注入名称为"z"的ZoneId
    ZoneId zoneId = ZoneId.systemDefault();
    ...
}

3. @Value注入资源Resource

IoC 容器不仅可以注入Bean,还可以注入资源文件 Resource。
工程目录如下


IoC注入资源文件
@Component
public class AppService {
    @Value("classpath:/logo.txt")
    private Resource resource;

    private String logo;

    @PostConstruct
    public void init() throws IOException {
        try (var reader = new BufferedReader(
                new InputStreamReader(resource.getInputStream(), StandardCharsets.UTF_8))) {
            this.logo = reader.lines().collect(Collectors.joining("\n"));
        }
    }
}

4. @PropertySource 注入配置

一般来说,很多配置项都以 key=value 的形式写在 .properties 文件中。
我们可以通过 @PropertySource 来注入配置,直接读取。

@Configuration
@ComponentScan
@PropertySource('app.propertires')
public class AppConfig{
    @Value("${app.zone:z}")
    String zoneId;

    @Bean
    ZoneId createZoneId() {
        return ZoneId.of(zoneId);
    }
}

可以看到,这里首先通过 @PropertySource 注入配置文件,然后通过 @value 注入key为app.zone 的value


5. 使用@Profile条件装配

这里主要是为了区分不同的环境,例如

相关文章

网友评论

      本文标题:Spring学习(四)-- IoC 容器高级用法

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