@Conditional注解详解

目录

一、@Conditional注解作用

 二、@Conditional源码解析

2.1 Conditional源码

2.2 Condition源码

三、Conditional案例

3.1 Conditional作用在类上案例

3.1.1 配置文件

3.1.2 Condition实现类

3.1.3 Bean内容类

3.1.4 Config类

3.1.5 Controller类

3.1.6 测试结果

3.2 Condition作用在类上且多个条件

3.2.1 增加一个Condition实现类

3.2.2 Config2类

3.3 @Conditional注入到方法上

3.3.1 Bean内容类

3.3.2 Condition实现类

3.3.3 Config配置类

3.3.4 Controller测试类

3.3.5 测试结果

 四、@Conditional系列注解拓展

4.1 @Component容器和@Bean容器的区别

4.2 @Conditonal注解拓展

4.2.1 @ConditionalOnClass

4.2.1.1 config类

4.2.1.2 Controller类

4.2.1.3  结果

4.2.2 @ConditionalOnMissingClass

4.2.2.1 Config

4.2.2.2 Controller

4.2.2.3 测试

4.2.3 @ConditionalOnBean

4.2.3.1 config

4.2.3.2 Controller

 4.2.3.3 测试结果

4.2.4 @ConditionalOnSingleCandidate

4.2.4.1 config

 4.2.4.2 Controller

 4.2.4.3 测试结果

4.2.5 @ConditionalOnWebApplication

4.2.5.1 config

4.2.5.2 Controller

 4.2.5.3 结果

4.2.6 @ConditionalOnProperty

4.2.6.1 yml文件内容

4.2.6.2 config

4.2.6.3 Contoller

4.2.6.4 测试结果


一、@Conditional注解作用

Conditional中文翻译是条件的意思,@Conditional注解的作用是按照一定的条件进行判断,满足条件给容器注册bean。

 二、@Conditional源码解析

2.1 Conditional源码

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Conditional {
    Class<? extends Condition>[] value();
}

从源码中可以看到,@Conditional只有一个数组参数,也就是说明,传递的参数是可以多个的,但这个参数是要求继承Condition类。 

2.2 Condition源码

@FunctionalInterface
public interface Condition {
    boolean matches(ConditionContext var1, AnnotatedTypeMetadata var2);
}

Condition是一个函数式接口,matches就是它的比较方法,如果为true,那么就注入,如果为false,则不注入

三、Conditional案例

3.1 Conditional作用在类上案例

3.1.1 配置文件

enable:
  flag: true

3.1.2 Condition实现类

public class TestCondition implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata annotatedTypeMetadata) {
        Environment environment = context.getEnvironment();
        String flagString = environment.getProperty("enable.flag");
        // 如果flagString为true,则直接返回true
        if(Boolean.parseBoolean(flagString)){
            return true;
        }
        return false;
    }
}

3.1.3 Bean内容类

public class TestBean {

    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return name + "是TestBean";
    }
}

3.1.4 Config类

@Conditonal注解作用在类上,并且判断的条件只有一个

@Configuration
@Conditional(TestCondition.class)
public class TestConfig {

    @Bean
    public TestBean testBean(){
        TestBean testBean = new TestBean();
        testBean.setName("java");
        testBean.toString();
        return testBean;
    }
}

3.1.5 Controller类

controller用于测试

注意点:@Autowired注解后面建议加上required=false,这样就算Condition实现类(对应上面的TestCondition类)返回的结果为false,那么项目也不会启动报错,如果没有加上,当Condition实现类返回为false的时候,项目启动过程会报Field config in com.common.commonframework.TestController required a bean of type 'com.common.commonframework.TestConfig' that could not be found.错误

@RestController
public class TestController {

    //如果为false,启动的时候在这一步会报错,可以添加成
   @Autowired(required = false)
    private TestConfig config;

    @GetMapping("/test")
    public void printImportBeanInfo() {
        System.out.println(config);
        System.out.println(config.testBean());
    }

}

3.1.6 测试结果

3.2 Condition作用在类上且多个条件

3.2.1 增加一个Condition实现类

public class TestCondition2 implements Condition {
    @Override
    public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
        //直接返回false,用于测试
        return false;
    }
}

3.2.2 Config2类

@Conditional多个条件

注意点:下面的代码由于TestConditon2知己诶返回的是false,所以是一定会注入失败的

// TestCondition为false,所以在这个地方是一定会注入失败的
@Configuration
@Conditional({TestCondition.class,TestCondition2.class})
public class TestConfig2 {
    @Bean
    public TestBean testBean(){
        return new TestBean();
    }
}

3.3 @Conditional注入到方法上

3.3.1 Bean内容类

public class TestBean2 {

    private String address;

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return "测试方法Bean";
    }
}

3.3.2 Condition实现类

这个实现类直接返回结果直接为false,用于测试

public class TestCondition3 implements Condition {
    @Override
    public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
        return false;
    }
}

3.3.3 Config配置类

@Configuration
public class TestConfig3 {

    @Bean
    @Conditional({TestCondition3.class})
    public TestBean2 testBean3(){
        TestBean2 testBean2 = new TestBean2();
        testBean2.setAddress("上海");
        return  testBean2;
    }
}

3.3.4 Controller测试类

@RestController
public class TestController {
    
    @Autowired
    private TestConfig3 config3;

    @GetMapping("/test")
    public void printImportBeanInfo() {
        //因为@Conditional修饰的是在方法上,,所以TestConfig3是会注入进去的
        System.out.println(config3);
        System.out.println(config3.testBean3());
    }
}

3.3.5 测试结果

由于在TestConfig3的方法上面修饰的@Conditonal注解返回的是false,所以我们在调用对应的Bean的时候会直接报"No bean named ''xx" available"错误

 四、@Conditional系列注解拓展

springboot提供的@Conditonal系列注解作用:对@Component,@Bean等容器注解进行校验。校验是否满足指定的条件,只有满足指定的条件时,才会将对应的内容放到容器里面。如果在启动过程当中,直接报了@Bean容器重复,那么建议直接用@Conditional注解处理。

4.1 @Component容器和@Bean容器的区别

@Component作用于类,@Bean作用于方法

@Component是通过路劲扫描的方式自动装配到bean容器中,而@Bean是将方法返回值作为bean自动装配到IOC容器中

@Bean功能比@Component的功能更加强大,当我们需要引用外部类,并需要将它注入到IOC容器时,@Component注解是做不到的,但@Bean可以做到。

4.2 @Conditonal注解拓展

4.2.1 @ConditionalOnClass

当给定的类名在类路径上存在,则实例化当前Bean

4.2.1.1 config类

TestBean2类在文章的上面

@Configuration
public class TestConfig4 {

    @Bean
    @ConditionalOnClass(TestBean2.class) //当TestBean2存在,那么这个bean就会注入到容器
    public TestBean2 testBean3(){
        TestBean2 testBean2 = new TestBean2();
        testBean2.setAddress("北京");
        return  testBean2;
    }

    @Bean
    @ConditionalOnClass(name = "com.common.commonframework.TestBean2") //也可以通过路径直接获取对应的类
    public TestBean2 testBean4(){
        TestBean2 testBean2 = new TestBean2();
        testBean2.setAddress("北京");
        return  testBean2;
    }
}
4.2.1.2 Controller类
@RestController
public class TestController {

    @Autowired
    private TestConfig4 config4;

    @GetMapping("/test")
    public void printImportBeanInfo() {
        System.out.println(config4);
        System.out.println(config4.testBean3());
        System.out.println(config4.testBean4());
    }
}
4.2.1.3  结果

因为TestBean2这个类存在,所以成功注入

4.2.2 @ConditionalOnMissingClass

当给定的类名在类路径上不存在,则实例化当前Bean

4.2.2.1 Config
@Configuration
public class TestConfig5 {

    @Bean
    @ConditionalOnMissingClass({ "com.common.commonframework.TestBean2"}) // 如果不存在TestBean2这个类,就将Bean注入容器,目前存在,所以会失败
    public TestBean2 testBean3(){
        TestBean2 testBean2 = new TestBean2();
        testBean2.setAddress("北京");
        return  testBean2;
    }
}
4.2.2.2 Controller
@RestController
public class TestController {

    @Autowired
    private TestConfig5 config5;

    @GetMapping("/test")
    public void printImportBeanInfo() {
        System.out.println(config5);
        System.out.println(config5.testBean3());
    }
}
4.2.2.3 测试

提示失败,因为TestBean2是存在的

4.2.3 @ConditionalOnBean

当给定的在bean存在时,则实例化当前Bean

4.2.3.1 config
@Configuration
public class TestConfig6 {

    @Bean
    public TestBean testBean(){
        TestBean testBean = new TestBean();
        testBean.setName("java");
        testBean.toString();
        return testBean;
    }

    @Bean
    @ConditionalOnBean(name = "testBean") //这个会成功,因为存在testBean这个容器
    public TestBean2 testBean3(){
        TestBean2 testBean2 = new TestBean2();
        testBean2.setAddress("北京");
        return  testBean2;
    }

    @Bean
    @ConditionalOnBean(name = "testBean2") //这个会失败,因为不存在testBean2这个Bean
    public TestBean2 testBean4(){
        TestBean2 testBean2 = new TestBean2();
        testBean2.setAddress("北京");
        return  testBean2;
    }
}
4.2.3.2 Controller
@RestController
public class TestController {

    @Autowired
    private TestConfig6 config6;

    @GetMapping("/test")
    public void printImportBeanInfo() {
        System.out.println(config6);
        System.out.println(config6.testBean3());
        System.out.println(config6.testBean4());
    }
}
 4.2.3.3 测试结果

testBean3成功,testBean4失败

4.2.4 @ConditionalOnSingleCandidate

只有指定的类已存在于BeanFactroy容器中,且只有一个实例时,才会作为bean放到容器。如果有多个,则指定首选的bean。@ConditionalOnSingleCandidate是@ConditionalOnBean的一种情况,满足前者时一定满足后者,满足后者时不一定满足前者

4.2.4.1 config

下面的案例是自定义bean然后注入到BeanFactory之中,springboot实际上有很多bean在启动过程当中会自动注入BeanFactory,不需要我们手动再去注入BeanFactory,比如我们常用的RedisConnectionFactory等等

@Configuration
public class TestConfig7  implements InitializingBean, BeanFactoryAware {

    public ConfigurableListableBeanFactory beanFactory;

    @Bean
    @ConditionalOnSingleCandidate //自定义的bean注入了BeanFactory所以会成功
    public TestBean testBean(){
        TestBean testBean = new TestBean();
        testBean.setName("java");
        testBean.toString();
        return testBean;
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = (beanFactory instanceof ConfigurableListableBeanFactory)
                ? (ConfigurableListableBeanFactory) beanFactory : null;
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        TestBean testBean = new TestBean();
        testBean.setName("java");
        testBean.toString();
        beanFactory.registerSingleton("testBean",testBean);
    }
}
 4.2.4.2 Controller
@RestController
public class TestController {

    @Autowired
    private TestConfig7 config7;
    
    @GetMapping("/test")
    public void printImportBeanInfo() {
        System.out.println(config7);
        System.out.println(config7.testBean());
    }
}
 4.2.4.3 测试结果

4.2.5 @ConditionalOnWebApplication

指定对应的web应用类型,才会做为bean放到容器中

4.2.5.1 config
@Configuration
public class TestConfig8 {

    @Bean
    @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET) //web应用类型是servlet应用就会注入bean
    public TestBean testBean(){
        TestBean testBean = new TestBean();
        testBean.setName("java");
        testBean.toString();
        return testBean;
    }

    @Bean
    @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE) //web应用类型是reactive应用就会注入bean
    public TestBean testBean2(){
        TestBean testBean = new TestBean();
        testBean.setName("java");
        testBean.toString();
        return testBean;
    }
}
4.2.5.2 Controller
@RestController
public class TestController {

    @Autowired
    private TestConfig8 config8;

    @GetMapping("/test")
    public void printImportBeanInfo() {
        System.out.println(config8);
        System.out.println(config8.testBean());
        System.out.println(config8.testBean2());
    }
}
 4.2.5.3 结果

从结果可以看到一个testBean成功,一个testBean2失败,因为我的应用类型是servlet

4.2.6 @ConditionalOnProperty

yml或者properties文件,只有当配置条件满足要求时,才会放到bean容器

4.2.6.1 yml文件内容
conditional:
  test: 1
4.2.6.2 config
@Configuration
public class TestConfig9 {

    @Bean
    @ConditionalOnProperty("conditional.test")
    public TestBean testBean(){
        TestBean testBean = new TestBean();
        testBean.setName("java");
        testBean.toString();
        return testBean;
    }

    @ConditionalOnProperty("conditional.test.test")
    @Bean
    public TestBean testBean2(){
        TestBean testBean = new TestBean();
        testBean.setName("java");
        testBean.toString();
        return testBean;
    }
}
4.2.6.3 Contoller
@RestController
public class TestController {

    @Autowired
    private TestConfig9 config9;

    @GetMapping("/test")
    public void printImportBeanInfo() {
        System.out.println(config9);
        System.out.println(config9.testBean());
        System.out.println(config9.testBean2());
    }
}
4.2.6.4 测试结果

因为testBean对应的配置存在,所以会成功,testBean2对应的配置在配置文件不存在,所以失败了

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/450032.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

ELK 日志分析系统

ELK &#xff08;Elasticsearch、Logstash、Kibana&#xff09;日志分析系统的好处是可以集中查看所有服务器日志&#xff0c;减轻了工作量&#xff0c;从安全性的角度来看&#xff0c;这种集中日志管理可以有效查询以及跟踪服务器被攻击的行为。 Elasticsearch 是个开源分布式…

酷柚易汛ERP - 采集助手使用文档说明

1、首先购买采集助手插件 2、管理员进入采集助手可配置对应的API KEY 3、到对应电商去复制商品链接&#xff0c;进行基础数据采集 4、采集成功后可对商品进行编辑&#xff0c;进行快速同步到ERP商品库中

CUDA环境配置在Ubuntu18

&#x1f3ac;个人简介&#xff1a;一个全栈工程师的升级之路&#xff01; &#x1f4cb;个人专栏&#xff1a;高性能&#xff08;HPC&#xff09;开发基础教程 &#x1f380;CSDN主页 发狂的小花 &#x1f304;人生秘诀&#xff1a;学习的本质就是极致重复! 目录 1 NVIDIA CU…

FastAPI 学习笔记

FastAPI 学习笔记 0. 引言1. 快速开始2. 升级示例代码 0. 引言 在 Python 这个充满活力的生态系统中&#xff0c;FastAPI 应运而生&#xff0c;它是一个现代的、快速的 Web 框架&#xff0c;专注于构建 RESTful API。 无论你是一名有经验的 Python 开发人员&#xff0c;还是一…

ArcGIS学习(十四)OD分析

ArcGIS学习(十四)OD分析 1.上海市KFC与麦当劳的空间聚集度分析 本任务给大家带来的内容是网络节点关系分析。网络节点关系分析一般也叫OD分析。“O”指的是起点(ORIGIN),"D”指的是终点(DESTINATION),0D分析即为基于起点到终点的分析。 网络节点关系分析我们经常…

23-Java空对象模式 ( Null Object Pattern )

Java空对象模式 实现范例 在空对象模式&#xff08;Null Object Pattern&#xff09;中&#xff0c;一个空对象取代 NULL 对象实例的检查Null 对象不是检查空值&#xff0c;而是反应一个不做任何动作的关系&#xff0c;这样的 Null 对象也可以在数据不可用的时候提供默认的行为…

1. OSPF 基础实验(三):邻接关系和 LSA

1.3 OSPF 的邻接关系和 LSA 1.3.1 实验介绍 1.3.1.1 学习目标 1. 阐明在多路访问网络中接入多台路由器时的邻居关系建立过程 2. 控制 OSPF DR 的选举 3. 描述 5 种类型的 LSA 的内容&#xff0c;以及它们的作用 1.3.1.2 实验组网介绍 设备互联方式及 IP 地址规划如图所示…

NASA数据集——亚马逊盆地与其大气边界层之间各种气溶胶和气体交换率的估计值数据

简介 Pre-LBA ABLE-2A and ABLE-2B Expedition Data ABLE 2A 和 2B&#xff08;大气边界层实验&#xff09;数据包括亚马逊盆地与其大气边界层之间各种气溶胶和气体交换率的估计值&#xff0c;以及这些气溶胶和气体在边界层和自由对流层之间的移动过程。前言 – 人工智能教程…

【五】【算法分析与设计】双指针的初见

167. 两数之和 II - 输入有序数组 给你一个下标从 1 开始的整数数组 numbers &#xff0c;该数组已按 非递减顺序排列 &#xff0c;请你从数组中找出满足相加之和等于目标数 target 的两个数。如果设这两个数分别是 numbers[index(1)] 和 numbers[index(2)] &#xff0c;则 1 &…

Java项目源码基于springboot的家政服务平台的设计与实现

大家好我是程序员阿存&#xff0c;在java圈的辛苦码农。辛辛苦苦板砖&#xff0c;今天要和大家聊的是一款Java项目源码基于springboot的家政服务平台的设计与实现&#xff0c;项目源码以及部署相关请联系存哥&#xff0c;文末附上联系信息 。 项目源码&#xff1a;Java基于spr…

[计算机效率] 便笺的使用

2.4 便笺 便笺程序是一种方便用户记录、查看和编辑便签的简单应用程序。在Windows系统中&#xff0c;便笺通常作为系统自带的实用工具之一&#xff0c;可以帮助用户快速创建、编辑和组织便签&#xff0c;以便随时记录重要的信息、任务或提醒事项。 便笺程序通常具有以下特点&a…

岩土工程监测中振弦采集仪的选型指南与市场概况

岩土工程监测中振弦采集仪的选型指南与市场概况 振弦采集仪是岩土工程监测中常用的一种设备&#xff0c;用于测量土体的振动特性。它的选型指南和市场概况如下&#xff1a; 选型指南&#xff1a; 1. 测量参数&#xff1a;振弦采集仪可用于测量土体的振动振幅、频率、相位等参数…

美团2025春招第一次笔试题

第四题 题目描述 塔子哥拿到了一个大小为的数组&#xff0c;她希望删除一个区间后&#xff0c;使得剩余所有元素的乘积未尾至少有k个0。塔子哥想知道&#xff0c;一共有多少种不同的删除方案? 输入描述 第一行输入两个正整数 n,k 第二行输入n个正整数 a_i&#xff0c;代表…

OpenHarmony开发—购物示例应用

介绍 本示例展示在进场时加载进场动画&#xff0c;整体使用Tabs容器设计应用框架&#xff0c;通过TabContent组件设置分页面&#xff0c;在子页面中绘制界面。通过Navigation完成页面之间的切换。在详情页中通过 Video组件加载视频资源&#xff0c;使用CustomDialogController…

力扣刷题日记——L66.加一

1. 前言&#xff1a; 从今天开始打卡力扣&#xff0c;每天一道力扣题&#xff0c;然后将解题思路分享出来&#xff0c;纯原创。 2. 题目描述 给定一个由 整数 ****组成的 ****非空 数组所表示的非负整数&#xff0c;在该数的基础上加一。 最高位数字存放在数组的首位&#…

使用API有效率地管理Dynadot域名,使用API设置域名隐私保护

关于Dynadot Dynadot是通过ICANN认证的域名注册商&#xff0c;自2002年成立以来&#xff0c;服务于全球108个国家和地区的客户&#xff0c;为数以万计的客户提供简洁&#xff0c;优惠&#xff0c;安全的域名注册以及管理服务。 Dynadot平台操作教程索引&#xff08;包括域名邮…

SiT技术报告阅读

论文链接&#xff1a;SiT: Exploring Flow and Diffusion-based Generative Models with Scalable Interpolant Transformers 报告链接&#xff1a;https://scalable-interpolant.github.io/ 文章目录 IntroFlow and DiffusionDiffusion-Based ModelsStochastic Interpolant an…

GPT出现Too many requests in 1 hour. Try again later.

换节点 这个就不用多说了&#xff0c;你都可以上GPT帐号了&#xff0c;哈…… 清除cooki 然后退出账号&#xff0c;重新登录即可

应用工程中获取Shapefile文件的图形信息并显示

本文用纯前端获取shp文件以及前后端交互的方式获取Shapefile文件中的图形信息 1.案例说明 在日常的WebGIS开发中&#xff0c;我们往往会面对&#xff0c;需要用户选择矢量数据&#xff0c;通过矢量数据中的空间范围信息&#xff0c;显示在界面上&#xff0c;并给用户的下一步…

wave库基本操作

wave 常见的语音信号处理python库有librosa, scipy, soundfile等等。wave库是python的标准库&#xff0c;对于python来说相对底层&#xff0c;wave不支持压缩/解压&#xff0c;但支持单声道/立体声语音的读取。 读取音频 import wavefile_path D:/ba.wav #文件路径 f wave…