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条件装配
这里主要是为了区分不同的环境,例如












网友评论