Spirng @Conditional 条件注解的使用

2023-11-12

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 jidi_jidi@163.com
 * @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 jidi_jidi@163.com
 * @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 jidi_jidi@163.com
 * @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存在时生效。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Spirng @Conditional 条件注解的使用 的相关文章

  • 在 Kotlin 中实现返回 Collection 的 Java 方法

    我将 Kotlin 与 Spring Security 结合使用 实现该方法时 public interface UserDetails extends Serializable Collection
  • JUnit 使用 Mockito 测试异步方法

    我已经使用 Spring Framework 版本 5 0 5 RELEASE 在 Java 1 8 类中实现了异步方法 public class ClassToBeTested Autowired private MyComponent
  • java“void”和“非void”构造函数

    我用 java 编写了这个简单的类 只是为了测试它的一些功能 public class class1 public static Integer value 0 public class1 da public int da class1 v
  • 在气球内显示带有照片的多个地标的最佳做法是什么?

    我有一个项目如下 从手机上拍摄几张照片 将照片保存在网络系统中 然后将照片显示在其中的谷歌地球上 我读过很多文章 但它们都使用 fetchKml 我读过的一篇好文章是使用 php 但使用 fetchKml 我不知道是否可以使用 parseK
  • 删除 servlet 中的 cookie 时出现问题

    我尝试使用以下代码删除 servlet 中的 cookie Cookie minIdCookie null for Cookie c req getCookies if c getName equals iPlanetDirectoryPr
  • 无法从后台服务通过 WiFi 访问互联网

    我将直接介绍我发现的一些事实 数据 如果您遇到 解决了类似的问题 请帮助我 我每 5 分钟向服务器发送一次数据 除非用户在服务器的帮助下手动将其关闭 wakeful broadcast receiver通过一个intent service
  • 业务代表与服务定位器

    Business Delegate 和 Service Locator 之间有什么区别 两者都负责封装查找和创建机制 如果 Business Delegate 使用 Service Locator 来隐藏查找和创建机制 那么 Busines
  • 如何模拟一个方面

    我目前正在使用aspectj 开发一些监控工具 因为这个工具应该是技术独立的 尽可能 所以我没有使用 Spring 进行注入 但我希望我的方面能够经过单元测试 方面示例 Aspect public class ClassLoadAspect
  • 会话 bean 中的 EntityManager 异常处理

    我有一个托管无状态会话 bean 其中注入了 EntityManager em 我想做的是拥有一个具有唯一列的数据库表 然后我运行一些尝试插入实体的算法 但是 如果实体存在 它将更新它或跳过它 我想要这样的东西 try em persist
  • Java G1 GC 处理引用对象运行缓慢

    我已经在 J ava 上运行了计数器 它24小时工作 每秒点击通过100次左右 白天 GC 处理时间从 20 60 毫秒缓慢上升到 10000 60000 毫秒 然后下降到 20 60 毫秒 这种模式不时地重复 从 GC 日志中我发现 GC
  • Java String.format 向整数添加空格

    我有一小段代码 我不明白输出 此输出向我的字符串格式文本添加空格 我做错了什么吗 public class HelloWorld public static void main String args int a1 540 int a2 4
  • 哪种 Java DOM 包装器是最好或最受欢迎的? [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • 存储过程将多个表返回到 spring jdbc 模板

    我正在使用 JdbcTemplate 从 Spring DAO 类调用存储过程 我的问题是 存储过程返回多个表 有没有办法使用 Spring JdbcTemplate 访问多个表 如果我使用jdbcTemplate queryForList
  • 用 Java 创建迷宫求解算法

    我被分配了用 Java 创建迷宫求解器的任务 这是任务 Write an application that finds a path through a maze The maze should be read from a file A
  • Mule/码头设置

    我有一个正在运行的 Mule 应用程序 我想在其上设置 Jetty 来响应 http 请求 以下配置
  • 将字符串中的字符向左移动

    我是 Stack Overflow 的新手 有一道编程课的实验室问题一直困扰着我 该问题要求我们将字符串 s 的元素向左移动 k 次 例如 如果输入是 Hello World 和3 它将输出 lo WorldHel 对于非常大的 k 值 它
  • Android同步onSensorChanged?

    这是我的问题的后续 Android线程可运行性能 https stackoverflow com questions 36395440 android thread runnable performance 我在理解应用程序的同步方法时遇到
  • JDK 7 的快速调试/调试构建

    我正在寻找 JDK 的调试 或者我猜他们称之为快速调试构建 以启用在运行时生成的打印程序集以及查找性能问题时所需的其他诊断 就目前情况而言 我似乎找不到可以直接使用的 现成的 快速调试构建二进制包 有人可以帮我提供下载链接 或者至少提供有关
  • Java 9 中紧凑字符串和压缩字符串的区别

    有什么优点紧凑的字符串 http openjdk java net jeps 254JDK9 中的压缩字符串 压缩字符串 Java 6 和紧凑字符串 Java 9 都有相同的动机 字符串通常实际上是 Latin 1 因此浪费了一半的空间 和
  • 如何使用 Spring AOP 建议静态方法?

    在执行类的静态方法之前和之后需要完成一些日志记录 我尝试使用 Spring AOP 来实现这一点 但它不起作用 而对于正常方法来说它起作用 请帮助我理解如何实现这一点 如果可以使用注释来完成 那就太好了 也许您应该在使用 Spring AO

随机推荐

  • Java设计之道——通过UML理解23种设计模式

    文章目录 UML类图 泛化 generalize 与实现 realize 聚合 aggregation 与组合 composition 关联 association 与依赖 dependency 23种设计模式 创建型模式 结构型模式 行为
  • webpack使用CMD、AMD、CommonJS、ES6区别以及运用

    之前在网上浏览器的webpack模块化很乱 而且也没有把CMD模块化使用讲清楚的 终于忍不下去 将几种模块化以一种清晰的方式写出来 这也是我一直想做的事 下面就来讲讲CMD AMD commonJs es6模块化的运用 CMD CMD是se
  • 编译出现:failed to compile bitcode for ***: Debug: SDK path: /Applications/Xcode.app/Contents

    解决方法 MyProjectTarget gt Build Settings gt Enable Bitcode NO
  • Notepad++添加读取十六进制插件HexEditor

    下载地址 https github com chcg NPP HexEdit releases 安装方式 下载压缩包 例如 HexEditor 0 9 5 19 x64 zip 解压到本地目录 将文件夹更名为HexEditor 打开Note
  • Linux基础服务9——Tomcat

    文章目录 一 基本了解 二 安装tomcat 三 常用文件 3 1 bin目录文件 3 2 conf目录文件 3 2 1 server xml文件 3 2 2 tomcat users xml 文件 四 分离部署lamt架构 4 1 安装h
  • 螺旋矩阵的实现

    螺旋矩阵就是形如如下图的矩阵 看到矩阵知道它由四条边组成 这样的话就有这样的n 2个环 但是如果是奇数矩阵的话在最中间需要特殊处理一下 代码如下 include
  • 攻防世界之Web新手练习篇

    前言 天行健 君子以自强不息 地势坤 君子以厚德载物 周易 第一次接触CTF比较晚 学期已过近半 第一次做题就是在攻防世界 这里题目适合刚接触的萌新 写此篇博客 以为纪念 首页 目录 View source robots backup co
  • CentOS 初体验三: Yum 安装、卸载软件

    转载请标明出处 http blog csdn net zhaoyanjun6 article details 78894974 本文出自 赵彦军的博客 一 Yum 简介 Yum 全称为 Yellow dog Updater Modified
  • Unity3D服务器端使用PhysX计算物理

    本文的最终目的 当设计师在Unity3D中制作好游戏场景后 为Gameobject拖好Collider 通过我们写的工具导出这份场景的Collider配置 在服务器端能够生成一份一模一样的物理世界 从而由权威服务器去计算物理 诸如子弹有没有
  • FM/AM收音机原理

    收音机这东西很早就开始用了 但一直都没有了解过它的原理 听说是很简单 下面记录一些笔记 1 基本概念 收音机是一种小型的无线电接收机 主要用于接受无线电广播节目 收听无线电发射台 首先说一下收音机的种类 按解调方式和波长可以分为以下几类 调
  • VSCode加入Anaconda大家庭

    此文章首发于公众号Python for Finance 链接 https mp weixin qq com s rZsopAtS8UZ32aohWuhVBA 问题描述 我安装的是Anaconda 但最近发现VScode编辑ipynb非常好使
  • Ubuntu虚拟机找不到终端

    快捷键 Ctrl Alt T 即可打开终端窗口 或者按 Ctrl Alt F1 F6 均可进入终端 模拟终端 不显示桌面 想要右键打开终端 apt get install nautilus open terminal 注销系统重新登录 即可
  • 局域网场景下Android客户端实现同数据库连接通信

    实现 局域网场景下 Android客户端连接数据库 并可进行增删改查 直接连接 项目工程引入JDBC驱动 直接连接 JDBC是Java Data Base Connectivity的缩写 即 java数据库连接 一组Java语言编写的类和接
  • JXL(JExcelApi)相关资源

    1 主页 2 下载页面 Download JExcelApi 3 JXL API Online 4 全面挖掘Java Excel API 使用方法 1 5 全面挖掘Java Excel API 使用方法 2 6 使用JAVA透過JXL JE
  • 在虚拟机上安装macOS和Xcode

    最近要开发iOS软件 开发软件的操作系统需要是macOS 开发工具是Xcode 虽然实验室有苹果电脑 但是还是想在自己电脑上安装macOS虚拟机和Xcode软件 这样的话在宿舍或者在家都能开发 按照网上的教程成功安装了macOS和Xcode
  • git 提交分支报错(不能提交分支)

    git 提交新分支报错 报错信息如下 Compressing objects 100 100 100 done Writing objects 100 229 229 25 18 KiB 3 15 MiB s done Total 229
  • 淘宝x-sign算法demo示例

    用xposed hook这个方法就可以拿到对应的签名 需要可以留言 public String getMtopApiSign HashMap
  • 图文并茂:推荐算法架构——粗排

    导语 粗排是介于召回和精排之间的一个模块 是典型的精度与性能之间trade off的产物 理解粗排各技术细节 一定要时刻把精度和性能放在心中 本篇将深入重排这个模块进行阐述 一 总体架构 粗排是介于召回和精排之间的一个模块 它从召回获取上万
  • bilibili粉丝显示器

    代码地址 https github com hungtcs lab bilibili follower viewer ArduinoJSON https arduinojson org esp8266 oled ssd1306 https
  • Spirng @Conditional 条件注解的使用

    1 简介 Conditional 是 Spring 4 0 提出的一个新的注解 当标注的对象满足所有的条件时 才能注册为 Spring 中的 bean Conditional 源码中的定义如下 Target ElementType TYPE