作用 @Conditional 是 Spring4 新提供的注解, 它的作用是按照一定的条件进行判断, 满足条件的才给容器注册 Bean.
一, 概述
1,@Conditional 注解定义
- @Target({ElementType.TYPE, ElementType.METHOD})
- @Retention(RetentionPolicy.RUNTIME)
- @Documented
- public @interface Conditional {
- Class<? extends Condition>[] value();
- }
- 2,Condition
我们点进去看后, 发现它是一个接口, 有一个方法.
- @FunctionalInterface
- public interface Condition {
- boolean matches(ConditionContext var1, AnnotatedTypeMetadata var2);
- }
- 3,ConditionContext
它持有不少有用的对象, 可以用来获取很多系统相关的信息, 来丰富条件判断, 接口定义如下
- public interface ConditionContext {
- /**
- * 获取 Bean 定义
- */
- BeanDefinitionRegistry getRegistry();
- /**
- * 获取 Bean 工程, 因此就可以获取容器中的所有 bean
- */
- @Nullable
- ConfigurableListableBeanFactory getBeanFactory();
- /**
- * environment 持有所有的配置信息
- */
- Environment getEnvironment();
- /**
- * 资源信息
- */
- ResourceLoader getResourceLoader();
- /**
- * 类加载信息
- */
- @Nullable
- ClassLoader getClassLoader();
- }
二, 案例
需求 根据当前系统环境的的不同实例不同的 Bean, 比如现在是 Mac 那就实例一个 Bean, 如果是 Windows 系统实例另一个 Bean.
1,SystemBean
首先创建一个 Bean 类
- @Data
- @AllArgsConstructor
- @NoArgsConstructor
- @ToString
- public class SystemBean {
- /**
- * 系统名称
- */
- private String systemName;
- /**
- * 系统 code
- */
- private String systemCode;
- }
2, 通过 Configuration 配置实例化 Bean
- @Slf4j
- @Configuration
- public class ConditionalConfig {
- /**
- * 如果 WindowsCondition 的实现方法返回 true, 则注入这个 bean
- */
- @Bean("windows")
- @Conditional({WindowsCondition.class})
- public SystemBean systemWi() {
- log.info("ConditionalConfig 方法注入 windows 实体");
- return new SystemBean("windows 系统","002");
- }
- /**
- * 如果 LinuxCondition 的实现方法返回 true, 则注入这个 bean
- */
- @Bean("mac")
- @Conditional({MacCondition.class})
- public SystemBean systemMac() {
- log.info("ConditionalConfig 方法注入 mac 实体");
- return new SystemBean("Mac ios 系统","001");
- }
- }
3,WindowsCondition 和 MacCondition
这两个类都实现了 Condition 接口, 只有 matches 方法返回 true 才会实例化当前 Bean.
- 1)WindowsCondition
- @Slf4j
- public class WindowsCondition implements Condition {
- /**
- * @param conditionContext: 判断条件能使用的上下文环境
- * @param annotatedTypeMetadata: 注解所在位置的注释信息
- */
- @Override
- public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
- // 获取 IoC 使用的 beanFactory
- ConfigurableListableBeanFactory beanFactory = conditionContext.getBeanFactory();
- // 获取类加载器
- ClassLoader classLoader = conditionContext.getClassLoader();
- // 获取当前环境信息
- Environment environment = conditionContext.getEnvironment();
- // 获取 bean 定义的注册类
- BeanDefinitionRegistry registry = conditionContext.getRegistry();
- // 获得当前系统名
- String property = environment.getProperty("os.name");
- // 包含 Windows 则说明是 Windows 系统, 返回 true
- if (property.contains("Windows")){
- log.info("当前操作系统是: Windows");
- return true;
- }
- return false;
- }
- }
- 2) MacCondition
- @Slf4j
- public class MacCondition implements Condition {
- @Override
- public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
- Environment environment = conditionContext.getEnvironment();
- String property = environment.getProperty("os.name");
- if (property.contains("Mac")) {
- log.info("当前操作系统是: Mac OS X");
- return true;
- }
- return false;
- }
- }
4, 测试类测试
- /**
- * @author xub
- * @date 2019/6/13 下午 10:42
- */
- @SpringBootTest(classes = Application.class)
- @RunWith(SpringRunner.class)
- public class TestConditionOn {
- @Autowired
- private SystemBean Windows;
- @Autowired
- private SystemBean Mac;
- @Test
- public void test() {
- if (Windows != null) {
- System.out.println("windows =" + Windows);
- }
- if (Mac != null) {
- System.out.println("linux =" + Mac);
- }
- }
- }
运行结果
通过运行结果可以看出
1, 虽然配置两个 Bean, 但这里只实例化了一个 Bean, 因为我这边是 Mac 电脑, 所以实例化的是 Mac 的 SystemBean
2, 注意一点, 我们可以看出 Windows 并不为 null, 而是 Mac 实例化的 Bean. 说明 只要实例化一个 Bean 的, 不管你命名什么, 都可以注入这个 Bean.
修改一下
这里做一个修改, 我们把 ConditionalConfig 中的这行代码注释掉.
// @Conditional({WindowsCondition.class})
再运行下代码
通过运行结果可以看出, 配置类的两个 Bean 都已经注入成功了.
注意 当同一个对象被注入两次及以上的时候, 那么你在使用当前对象的时候, 名称一定要是两个 bean 名称的一个, 否则报错. 比如修改为
- @Autowired
- private SystemBean Windows;
- @Autowired
- private SystemBean Mac;
- @Autowired
- private SystemBean Linux;
在启动发现, 报错了.
意思很明显, 就是上面只实例化成功一个 SystemBean 的时候, 你取任何名字, 反正就是把当前已经实例化的对象注入给你就好了.
但是你现在同时注入了两个 SystemBean, 你这个时候有个名称为 Linux, 它不知道应该注入那个 Bean, 所以采用了报错的策略.
GitHub 源码 ` https://github.com/yudiandemingzi/SpringBootBlog
参考
1,Spring @Conditional 注解
只要自己变优秀了, 其他的事情才会跟着好起来 (中将 3)
posted on 2019-06-13 23:41 雨点的名字 阅读 (...) 评论 (...) 编辑 收藏
来源: https://www.cnblogs.com/qdhxhz/p/11020434.html