@Conditional注解详解

news2024/11/15 21:30:08

目录

一、@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对应的配置在配置文件不存在,所以失败了

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ChatGPT GPT4科研应用、数据分析与机器学习、论文高效写作、AI绘图技术

原文链接&#xff1a;ChatGPT GPT4科研应用、数据分析与机器学习、论文高效写作、AI绘图技术https://mp.weixin.qq.com/s?__bizMzUzNTczMDMxMg&mid2247596849&idx3&sn111d68286f9752008bca95a5ec575bb3&chksmfa823ad6cdf5b3c0c446eceb5cf29cccc3161d746bdd9f2…

Lim接口测试平台开展自动化的优势

一、数据对比 使用Lim接口测试平台后&#xff0c;相比以往采用Postman或excel关键字驱动带来的效率提升&#xff1a; 编写效率提升300%&#xff0c;原来10个步骤的用例&#xff0c;一个工作日调试编写只能输出6条&#xff0c;现在一天能输出18条。维护成本复杂度降低100%&…

Vue3.0里为什么要用 Proxy API 替代 defineProperty API

一、Object.defineProperty 定义&#xff1a;Object.defineProperty() 方法会直接在一个对象上定义一个新属性&#xff0c;或者修改一个对象的现有属性&#xff0c;并返回此对象 为什么能实现响应式 通过defineProperty 两个属性&#xff0c;get及set get 属性的 getter 函…

北斗卫星助力海上风电厂:打造海上绿色能源新时代

北斗卫星助力海上风电厂&#xff1a;打造海上绿色能源新时代 近日&#xff0c;东海航海保障中心温州航标处在华能苍南海上风电场完成首套北斗水上智能感知综合预警系统现场安装调试工作&#xff0c;经现场效能测定&#xff0c;能有效保障海上风电场运行安全和海域船舶通航安全…

华为OD机试 - 模拟数据序列化传输(Java JS Python C C++)

题目描述 模拟一套简化的序列化传输方式,请实现下面的数据编码与解码过程 编码前数据格式为 [位置,类型,值],多个数据的时候用逗号分隔,位置仅支持数字,不考虑重复等场景;类型仅支持:Integer / String / Compose(Compose的数据类型表示该存储的数据也需要编码)编码后数…

光电容积脉搏波PPG信号分析笔记

1.脉搏波信号的PRV分析 各类分析参数记参数 意义 公式 参数意义 线性分析 时域分析 均值MEAN 反应RR间期的平均水平 总体标准差SDNN 评估24小时长程HRV的总体变化&#xff0c; SDNN &#xff1c; 50ms 为异常&#xff0c;SDNN&#xff1e;100ms 为正常&#xff1b;…

如何解决爬虫程序访问速度受限问题

目录 前言 一、代理IP的获取 1. 自建代理IP池 2. 购买付费代理IP 3. 使用免费代理IP网站 二、代理IP的验证 三、使用代理IP进行爬取 四、常见问题和解决方法 1. 代理IP不可用 2. 代理IP速度慢 3. 代理IP被封禁 总结 前言 解决爬虫程序访问速度受限问题的一种常用方…

群晖部署私人聊天服务器Vocechat并结合内网穿透实现公网远程访问

文章目录 1. 拉取Vocechat2. 运行Vocechat3. 本地局域网访问4. 群晖安装Cpolar5. 配置公网地址6. 公网访问小结 7. 固定公网地址 如何拥有自己的一个聊天软件服务? 本例介绍一个自己本地即可搭建的聊天工具,不仅轻量,占用小,且功能也停强大,它就是Vocechat. Vocechat是一套支持…

怎么把视频变成gif动图?一招在线生成gif动画

MP4是一种常见的视频文件格式&#xff0c;它是一种数字多媒体容器格式&#xff0c;可以用于存储视频、音频和字幕等多种媒体数据。MP4格式通常用于在计算机、移动设备和互联网上播放和共享视频内容。要将MP4视频转换为GIF格式&#xff0c;您可以使用专门的视频转gif工具。这个工…

中科数安|——如何防止别人复制文档内容?

#如何防止别人复制文档内容# 中科数安所提供的防止别人复制文档内容的措施主要包括但不限于以下几个方面&#xff1a; www.weaem.com 1. **文档加密与权限控制**&#xff1a; - 对关键文档进行加密处理&#xff0c;确保只有获得授权的人员才能解密并查看文档内容。 - 实施精…

Java项目:基于Springboot+vue实现的付费自习室系统设计与实现(源码+数据库+毕业论文)附含微信小程序端代码

一、项目简介 本项目是一套基于Springbootvue实现的付费自习室系统 包含&#xff1a;项目源码、数据库脚本等&#xff0c;该项目附带全部源码可作为毕设使用。 项目都经过严格调试&#xff0c;eclipse或者idea 确保可以运行&#xff01; 该系统功能完善、界面美观、操作简单、…

即时设计是什么?设计大佬在线讲解

即时设计是一种互联网产品设计工具。产品原型设计软件由以下四个部分介绍&#xff1a; 1、什么是即时设计&#xff1f; 2、即时设计产品和服务怎么样&#xff1f; 3、即时设计的优点是什么&#xff1f;优点是什么&#xff1f; 4、即时设计的客户是什么&#xff1f;哪些公司…

windows的vmdk文件转qcow2运行蓝屏

背景 使用qemu-img将做好的vmware虚拟机转为qcow2到gns3中运行&#xff0c;Linux、Win7、Win10都没出现蓝屏&#xff0c;但Win XP却在开机时蓝屏了&#xff0c;错误代码&#xff1a;0x0000007B 解决方案 最终在proxmox上找到方案&#xff1a;https://pve.proxmox.com/wiki/Ad…

(一区)基于模型的连续和离散全局优化方法

Model-based methods for continuous and discrete global optimization 1.摘要 本文综述了下基于模型的连续和离散全局优化方法&#xff0c;并提出了一种叠加替代信息的新方法。 2.介绍 比较水。。作者说&#xff0c;本文是首次尝试提供对连续和离散建模方法的可理解的调查…

微信自动回复的优势及设置方法

自动回复功能的优势&#xff1a; 1、可设置不重复触发时间和生效时间段&#xff0c;回复效果更智能&#xff0c;提升联系人体验&#xff1b; 2、可以多微信同时设置&#xff0c;可直接导入素材库内容&#xff0c;提高工作效率&#xff1b; 3、多个关键词、多条回复内容&…

可视化表单流程编辑器为啥好用?

想要提升办公率、提高数据资源的利用率&#xff0c;可以采用可视化表单流程编辑器的优势特点&#xff0c;实现心中愿望。伴随着社会的进步和发展&#xff0c;提质增效的办公效果一直都是很多职场办公团队的发展需求&#xff0c;作为低代码技术平台服务商&#xff0c;流辰信息团…

FreeRTOS操作系统学习——事件组

事件组介绍 一个事件组就是一组的事件位&#xff0c;事件组中的事件位通过位编号来访问。事件位用来表明某个事件是否发生&#xff0c;事件位通常用作事件标志。 事件组用一个整数来表示&#xff0c;其中的高8位留给内核使用&#xff0c;只能用其他的位来表示事件。那么这个整…

Liinux——(网络)socket编程

预备知识 源IP地址和目的IP地址 在IP数据包头部中, 有两个IP地址, 分别叫做源IP地址, 和目的IP地址 认识端口号 端口号(port)是传输层协议的内容. 端口号是一个2字节16位的整数;端口号用来标识一个进程, 告诉操作系统, 当前的这个数据要交给哪个进程来处理;IP地址 端口号能…

碾压GPT-4!Claude3到底有多强?

2024年3月4日&#xff0c;官方宣布推出 Claude 3 模型系列&#xff0c;它在广泛的认知任务中树立了新的行业基准。该系列包括三个按能力递增排序的最先进模型&#xff1a;Claude 3 Haiku、Claude 3 Sonnet 和 Claude 3 Opus。每个后续模型都提供越来越强大的性能&#xff0c;允…

【C++】—— 建造者模式

目录 &#xff08;一&#xff09;概念详解 &#xff08;二&#xff09;代码详解 &#xff08;三&#xff09;建造者优缺点详解 &#xff08;一&#xff09;概念详解 建造者模式是⼀种创建型设计模式&#xff0c;使⽤多个简单的对象⼀步⼀步构建成⼀个复杂的对象&#xff0c…