Spring Boot 2 实战:使用 @Condition 注解来根据条件注入 Bean
2020-09-04 22:06
2196 查看
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的任何属性。 您还可以使用
havingValue和
matchIfMissing属性创建更高级的检查。
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 进行系统性的学习。
相关文章推荐
- java中构造方法的作用(非原创)
- SpringCloud实战 | 第五篇:SpringCloud整合OpenFeign实现微服务之间的调用
- Springboot整合Spring Cloud Kubernetes读取ConfigMap,支持自动刷新配置
- JAVA基础——特殊的类和方法(抽象类,抽象方法,内部类 )
- JAVA集合类简要笔记 - 内部类 包装类 Object类 String类 BigDecimal类 system类
- JAVA-数组的定义
- JAVA基础——类的基本结构
- 【Spring注解驱动开发】AOP核心类解析,这是最全的一篇了!!
- 【程序源代码】基于 SpringBoot 智慧云智能教育平台
- SpringCloud实战 | 第四篇:SpringCloud整合Gateway实现API网关
- 肥桃的Java学习记录15:List接口的子类,ArrayList 和 LinkedList
- 三年渣渣的诉说!面试大厂Java开发,这10道Spring问题不得不懂!
- java安装教程
- 【深入理解Java虚拟机】Java虚拟机运行时数据区
- 硬抗阿里支付宝高级Java岗三面(底层+高并发+集群+分布式+调优等)
- 在Spring中拦截器的使用
- Gradle - 使用 Java 预览特性
- 肥桃的Java学习记录14:泛型和通配符
- 肥桃的Java学习记录13:Date类 Calendar类
- 《spring源码解读》 - IoC 之解析 import 标签