zoukankan      html  css  js  c++  java
  • Spring Boot 2 实战:使用 @Condition 注解来根据条件注入 Bean

    640?wx_fmt=gif

    1. 前言

    我们经常会有根据条件来加载不同的接口。比如你查询目录下文件列表, Windows 下你会用 CMD 的 dir 命令,而 Linux 下你会使用 ls 命令。 熟悉 Spring Boot 自动配置的也知道 Spring Boot 能根据不同的实际情况启用不同的配置。这就是@Conditional注解在发挥作用。 该注解指定了在什么条件下创建 Bean 进行配置。

    2. @Conditional 注解

    Spring Boot 包含多个 @Conditional 注释,可以在@Configuration注解的类和@Bean注解方法中使用。@Conditional类型的注解,可以注解在类上,可以注解在Bean方法上,可以允许基于Spring Environment属性包含配置,可以仅允许在存在特定资源时包含配置。也可自定义,接下来我们来熟悉一下 Spring Boot 提供的一些具体的条件注解。

    2.1 Class Conditions

    @ConditionalOnClass@ConditionalOnMissingClass 两个在类上的注解:

    判断指定的类是否存在来构建自动配置,也可使用name属性名来指定类名。

    2.2 Bean Conditions

    @ConditionalOnBean@ConditionalOnMissingBean 两个在 Bean 方法上的注解:

    判断指定的 Bean 是否存在来构建自动配置,可以使用value属性来按类型或名称(id)指定 Bean, 可以使用search属性指定 ApplicationContext 层次结构来搜索Bean

    @Configuration
    public class MyAutoConfiguration {
    
        @Bean
        @ConditionalOnMissingBean
        public MyService myService() { ... }
    
    }
    

    要添加注意添加 Bean 时的顺序,官方建议在自动配置类上仅使用 @ConditionalOnBean@ConditionalOnMissingBean注释,因为可以保证这些注释在添加用户定义的Bean后执行。

    @ConditionalOnBean@ConditionalOnMissingBean注解作用在@Configuration注释的类上,等同于在作用在每个包含@Bean的方法上。

    2.3 Property Conditions

    @ConditionalOnProperty注解可以基于Spring Environment属性包含的配置进判断,再决定自动配置的执行,使用 prefix 和 name 属性指定应检查的属性。默认情况下,匹配存在且不等于false的任何属性。 您还可以使用havingValuematchIfMissing属性创建更高级的检查。

    2.4 Resource Conditions

    @ConditionalOnResource注释仅允许在存在特定资源时执行自动配置。 可以使用常用的 Spring 约定来指定资源,如以下示例所示:file:/home/user/test.dat。

    2.5 Web Application Conditions

    @ConditionalOnWebApplication@ConditionalOnNotWebApplication注解用于判断应用程序是否为Web应用程序,Web应用程序是使用Spring WebApplicationContext,定义会话范围或具有StandardServletEnvironment的任何应用程序。

    2.6 SpEL Expression Conditions

    @ConditionalOnExpression注解允许根据SpEL表达式的结果来执行配置。

    3. 自定义 Condition

    如果上面几种都不能满足你的需要。那么我们可以通过实现Condition接口,并重写其matches方法来构造判断条件。

    • 1.实现 Condition 接口来定义判断条件

    //Windows系统的判断条件
    import org.springframework.context.annotation.Condition;
    import org.springframework.context.annotation.ConditionContext;
    import org.springframework.core.type.AnnotatedTypeMetadata;
    
    public class WindowsCondition implements Condition {
    
        @Override
        public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
            return context.getEnvironment().getProperty("os.name").contains("Windows");
        }
    }
    
    
    //Linux系统的判断条件
    import org.springframework.context.annotation.Condition;
    import org.springframework.context.annotation.ConditionContext;
    import org.springframework.core.type.AnnotatedTypeMetadata;
    
    public class LinuxCondition implements Condition {
    
        @Override
        public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
            return context.getEnvironment().getProperty("os.name").contains("Linux");
        }
    }
    
    • 2.实现不同系统下的Bean类

    //接口
    public interface ListService {
    
        public String showListCmd();
    }
    
    //Windows下的实现类
    public class WindowsListServiceImpl implements ListService {
    
        @Override
        public String showListCmd() {
            return "dir";
        }
    }
    
    //Linux下的实现类
    public class LinuxListServiceImpl implements ListService {
    
        @Override
        public String showListCmd() {
            return "ls";
        }
    }
    
    • 3.配置类

    @Conditional注解调用条件判断的类并根据返回的结果来创建Bean

    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Conditional;
    import org.springframework.context.annotation.Configuration;
    
    @Configuration
    public class ConditionConfig {
    
        @Bean
        @Conditional(WindowsCondition.class)
        public ListService windowsListService() {
            return new WindowsListServiceImpl();
        }
    
        @Bean
        @Conditional(LinuxCondition.class)
        public ListService linuxListService() {
            return new LinuxListServiceImpl();
        }
    }
    
    • 4. 测试

     @RunWith(SpringRunner.class)
     @SpringBootTest
    
     public class SecurityLearningApplicationTests {
    
         @Resource
         private ListService listService ;
         @Resource
         private ApplicationContext context;
    
    
    
    
         public void testCondition(){
             System.out.println(context.getEnvironment().getProperty("os.name")
                     + "系统下的列表命令:"
                     + listService.showListCmd());
         }
    
     }
    

    4. 总结

    今天我们对 Spring Boot 中的 Condition 条件判断注入进行了系统性的了解。不仅对 Spring Boot 提供的一些开箱即用的 Condition 进行了学习,还实现了自定义的 Condition 。如果你要对 Spring Boot 的自动配置深入学习或者根据业务来灵活定制,就必须对 Condition 进行系统性的学习。

    640?wx_fmt=gif

    ● 

     

     

    640?wx_fmt=png

    640?wx_fmt=gif

  • 相关阅读:
    模板
    kuangbin带你飞
    BZOJ开荒记
    模板
    洛谷
    模板
    [蓝桥杯][2013年第四届真题]危险系数
    数位DP入门题
    备战2019蓝桥杯
    常用的数学符号
  • 原文地址:https://www.cnblogs.com/felordcn/p/12142539.html
Copyright © 2011-2022 走看看