01 引言
前两天刷到大V程序员鱼皮视频面试现场,在直播面试的时候问到:怎么保证开发的SDK的时候,部分Bean
的实例化根据配置项实例化,没有配置就不实例化?
候选人支支吾吾半天,说到拦截器、过滤器等,就是没有条件注解,硬是逼着鱼皮自己说了。自然也就失去了这份Offer。
其实这个条件注解就是@Conditional
,它是 Spring4.0
版本框架的一个核心注解,专门用于 根据条件动态注册 Bean
。我们今天来了解一下这个注解。
02 案例
假设我们需要按照不同的环境初始化不同的Bean
,Windows下创建Windows相关的Bean
,Linux下创建Linux相关的Bean
。
2.1 Bean定义
Windows下的Bean
java
public class WindowBean {
public WindowBean() {
System.out.println("WindowBean 构造器执行完成");
}
}
Linux 下的Bean
java
public class LinuxBean {
public LinuxBean() {
System.out.println("LinuxBean 构造器执行完成");
}
}
2.2 配置
java
@Configuration
public class BeanConfig {
@Bean
public WindowBean windowBean() {
return new WindowBean();
}
@Bean
public LinuxBean linuxBean() {
return new LinuxBean();
}
}
2.3 启动测试
目前我们没有做任何的关于条件注解的配置,项目启动之后会这两个Bean都会被实例化。如图:
2.4 编写条件
根据环境变量os.name
匹配。
java
public class WindowsCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
String osName = context.getEnvironment().getProperty("os.name");
System.out.println("WindowsCondition osName: " + osName);
return "win".equals(osName);
}
}
public class LinuxCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
String osName = context.getEnvironment().getProperty("os.name");
System.out.println("LinuxCondition osName: " + osName);
return "linux".equals(osName);
}
}
2.5 修改配置
WindowBean
在匹配WindowsCondition
逻辑的时候,实例化Bean
。LinuxBean
在匹配LinuxCondition
逻辑的时候,才会实例化。
java
@Configuration
public class BeanConfig {
@Bean
@Conditional(WindowsCondition.class)
public WindowBean windowBean() {
return new WindowBean();
}
@Bean
@Conditional(LinuxCondition.class)
public LinuxBean linuxBean() {
return new LinuxBean();
}
}
启动命令上,增加os.name=win
的配置:
2.6 验证
03 源码追踪
因为使用的是注解,我们就直接看注解的上下文,以此为入口:
org.springframework.context.annotation.AnnotationConfigApplicationContext
关键代码块:
可以看到,在shouldSkip()
方法中,首先会判断类或方法上是否标注了@Conditional注解,如果没有标注@Conditional注解,则直接返回false。
此时,调用的doRegisterBean()
方法根据shouldSkip()
的返回,决定要不要把对应的Bean会被创建并注入到IOC容器中。
自此,条件注解的内幕也就被了。
04 扩展
其实我们在平时使用的时候,往往不会直接去用@Conditional
注解,反而经常会使用其扩展的注解,如下:
关注我的公众号获取首发内容:【编程朝花夕拾】