当前位置:网站首页>Spirng @Conditional 条件注解的使用
Spirng @Conditional 条件注解的使用
2022-07-25 11:45:00 【丑基地】
1、简介
@Conditional 是 Spring 4.0 提出的一个新的注解,当标注的对象满足所有的条件时,才能注册为 Spring 中的 bean。
@Conditional 源码中的定义如下:
@Target({
ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Conditional {
Class<? extends Condition>[] value();
}
可以看到 @Conditional 可以使用在类上或者方法上。具体使用方式如下:
1、 在标注或元标注了 @Component 组件的类上进行标注;
2、作为元注解直接标注在其他注解上面;
3、在标注了 @Bean 注解的方法上标注。
@Conditional 注解有一个 value 属性,其值只能为 Condition 类型的数组,使用 @Conditional 时必须进行指定(多个 Condition 是与的关系,多个条件需要都满足。默认按照定义的顺序指定,可以通过 @Order 对Condition 进行排序)。
Condition 是指具体的条件,是一个接口,需要自己实现。
@FunctionalInterface
public interface Condition {
/** * 确定条件是否匹配 */
boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);
}
Condition 是一个函数式接口,只有一个 matches 方法,返回 true 表示 Component 可以注册为 Spring 中的 bean。有两个参数:
1、 ConditionContext:表示条件的上下文信息;
public interface ConditionContext {
/** * 获取持有 BeanDefinition 的注册中心,BeanDefinition 是 Spring bean 的定义,BeanDefinitionRegistry 可以用来注册或查找 BeanDefinition。 */
BeanDefinitionRegistry getRegistry();
/** * 获取 BeanFactory,BeanFactory 是 spring 最基础的容器,保存有 spring 的 bean 实例 */
@Nullable
ConfigurableListableBeanFactory getBeanFactory();
/** * 获取当前应用运行的环境信息 */
Environment getEnvironment();
/** * 获取当前使用的 ResourceLoader,其可以用来加载各种各样的资源 */
ResourceLoader getResourceLoader();
/** * 获取加载其他类的 ClassLoader */
@Nullable
ClassLoader getClassLoader();
}
2、 AnnotatedTypeMetadata:表示类或方法上的注解元信息。
public interface AnnotatedTypeMetadata {
/** * 返回直接标注的注解详情 * @since 5.2 */
MergedAnnotations getAnnotations();
/** * 确定元素是否具有给定类型定义的注解或元注解 */
default boolean isAnnotated(String annotationName) {
return getAnnotations().isPresent(annotationName);
}
/** * 获取给定类型的注解属性,考虑属性重写 */
@Nullable
default Map<String, Object> getAnnotationAttributes(String annotationName) {
return getAnnotationAttributes(annotationName, false);
}
/** * 获取给定类型的注解属性,考虑属性重写 */
@Nullable
default Map<String, Object> getAnnotationAttributes(String annotationName, boolean classValuesAsString) {
MergedAnnotation<Annotation> annotation = getAnnotations().get(annotationName, null, MergedAnnotationSelectors.firstDirectlyDeclared());
if (!annotation.isPresent()) {
return null;
}
return annotation.asAnnotationAttributes(Adapt.values(classValuesAsString, true));
}
/** * 获取给定类型的所有注解的所有属性,不考虑属性重写 */
@Nullable
default MultiValueMap<String, Object> getAllAnnotationAttributes(String annotationName) {
return getAllAnnotationAttributes(annotationName, false);
}
/** * 获取给定类型的所有注解的所有属性,不考虑属性重写 */
@Nullable
default MultiValueMap<String, Object> getAllAnnotationAttributes(String annotationName, boolean classValuesAsString) {
Adapt[] adaptations = Adapt.values(classValuesAsString, true);
return getAnnotations().stream(annotationName)
.filter(MergedAnnotationPredicates.unique(MergedAnnotation::getMetaTypes))
.map(MergedAnnotation::withNonMergedAttributes)
.collect(MergedAnnotationCollectors.toMultiValueMap(map -> map.isEmpty() ? null : map, adaptations));
}
}
2、实战
要实现的目标:根据不同的环境,配置不同的线程池。步骤如下:
1、自定义 Condition,匹配条件:
/** * @Des 匹配本地开发环境 * @Author jidi * @Email [email protected] * @Date 2022/7/23 */
public class ProfilesActiveOfDevCondition implements Condition {
private static final String DEV = "dev";
@Override
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
// 获取配置属性 spring.profiles.active
Environment environment = conditionContext.getEnvironment();
String property = environment.getProperty("spring.profiles.active");
return Objects.equals(DEV, property);
}
}
/** * @Des 匹配生产环境 * @Author jidi * @Email [email protected] * @Date 2022/7/23 */
public class ProfilesActiveOfProCondition implements Condition {
private static final String PRO = "pro";
@Override
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
// 获取配置属性 spring.profiles.active
Environment environment = conditionContext.getEnvironment();
String property = environment.getProperty("spring.profiles.active");
return Objects.equals(PRO, property);
}
}
2、定义具体的线程池,通过 @Conditional 注解指定各自生效的环境:
/** * @Des * @Author jidi * @Email [email protected] * @Date 2022/7/23 */
@Configuration
@Slf4j
public class ApplicationConfig {
/** * 开发环境 */
@Bean
@Conditional(value = {
ProfilesActiveOfDevCondition.class})
public ThreadPoolExecutor devExecutor(){
ThreadPoolExecutor executor = new ThreadPoolExecutor(
2,
5,
60,
TimeUnit.SECONDS,
new ArrayBlockingQueue<>(100),
new ThreadPoolExecutor.CallerRunsPolicy());
// 预先初始化所有核心线程
executor.prestartAllCoreThreads();
log.info("初始化开发环境线程池!");
return executor;
}
/** * 生产环境 */
@Bean
@Conditional(value = {
ProfilesActiveOfProCondition.class})
public ThreadPoolExecutor proExecutor(){
ThreadPoolExecutor executor = new ThreadPoolExecutor(
5,
20,
60,
TimeUnit.SECONDS,
new ArrayBlockingQueue<>(1024),
new ThreadPoolExecutor.CallerRunsPolicy());
// 预先初始化所有核心线程
executor.prestartAllCoreThreads();
log.info("初始化生产环境线程池!");
return executor;
}
}
3、在配置文件中配置属性 spring.profiles.active,启动工程,即可根据不同的配置加载不同的线程池。
3、其他 @Conditional 扩展注解
除了 @Conditional 注解外,Spring 还内置了很多其他的条件注解,并且已经实现了它们的匹配逻辑,可以直接使。主要有以下注解:
1、@ConditionalOnBean:当Spring容器内存在指定Bean时生效;
2、@ConditionalOnMissingBean:当Spring容器内不存在指定Bean时生效;
3、@ConditionalOnClass:当Spring容器内存在指定Class时生效;
4、@ConditionalOnMissingClass:当Spring容器内不存在指定Class时生效;
5、@ConditionalOnProperty:当指定的属性满足匹配条件时生效;
6、@ConditionalOnResource:当类路径下有指定资源时生效;
7、@ConditionalOnWebApplication:当项目为web项目时生效;
8、@ConditionalOnNotWebApplication:当项目不为web项目时生效;
9、@ConditionalOnExpression:当SpEL表达式成立时生效;
10、@ConditionalOnJava:当满足JVM版本时生效;
11、@ConditionalOnJndi:当指定JNDI存在时生效。
边栏推荐
猜你喜欢

Client open download, welcome to try

2.1.2 机器学习的应用

Implement anti-theft chain through referer request header

Experimental reproduction of image classification (reasoning only) based on caffe resnet-50 network

Learning to pre train graph neural networks

Hystrix使用

投屏收费背后:爱奇艺季度盈利,优酷急了?

氢能创业大赛 | 国家能源局科技司副司长刘亚芳:构建高质量创新体系是我国氢能产业发展的核心

The first scratch crawler

Introduction to the scratch crawler framework
随机推荐
【五】页面和打印设置
Feign use
scrapy爬虫爬取动态网站
推荐系统-协同过滤在Spark中的实现
搭建Vision Transformer系列实践,终于见面了,Timm库!
客户端开放下载, 欢迎尝鲜
R language ggplot2 visualization: use the ggstripchart function of ggpubr package to visualize the dot strip chart, set the palette parameter to configure the color of data points at different levels,
Analysis of TCP packet capturing using Wireshark
Jenkins配置流水线
Ansible
R language uses LM function to build multiple linear regression model, step function to build forward stepwise regression model to screen the best subset of prediction variables, and scope parameter t
协程
记录一次线上死锁的定位分析
【十一】矢量、栅格数据图例制作以及调整
Musk's "eternal soul": half hype, half flicker
苹果供应链十年浮沉:洋班主任和它的中国学生们
web编程(二)CGI相关
通信总线协议一 :UART
Data transmission under the same LAN based on tcp/ip
[micro service ~sentinel] sentinel degradation, current limiting, fusing