@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 {@Overridepublic boolean matches(ConditionContext context, AnnotatedTypeMetadata annotatedTypeMetadata) {Environment environment = context.getEnvironment();String flagString = environment.getProperty("enable.flag");// 如果flagString为true,则直接返回trueif(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;}@Overridepublic String toString() {return name + "是TestBean";}
}

3.1.4 Config类

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

@Configuration
@Conditional(TestCondition.class)
public class TestConfig {@Beanpublic 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 {@Overridepublic 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 {@Beanpublic 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;}@Overridepublic String toString() {return "测试方法Bean";}
}

3.3.2 Condition实现类

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

public class TestCondition3 implements Condition {@Overridepublic 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 {@Autowiredprivate 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 {@Autowiredprivate 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 {@Autowiredprivate 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 {@Beanpublic 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这个Beanpublic TestBean2 testBean4(){TestBean2 testBean2 = new TestBean2();testBean2.setAddress("北京");return  testBean2;}
}
4.2.3.2 Controller
@RestController
public class TestController {@Autowiredprivate 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;}@Overridepublic void setBeanFactory(BeanFactory beanFactory) throws BeansException {this.beanFactory = (beanFactory instanceof ConfigurableListableBeanFactory)? (ConfigurableListableBeanFactory) beanFactory : null;}@Overridepublic 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 {@Autowiredprivate 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应用就会注入beanpublic TestBean testBean(){TestBean testBean = new TestBean();testBean.setName("java");testBean.toString();return testBean;}@Bean@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE) //web应用类型是reactive应用就会注入beanpublic TestBean testBean2(){TestBean testBean = new TestBean();testBean.setName("java");testBean.toString();return testBean;}
}
4.2.5.2 Controller
@RestController
public class TestController {@Autowiredprivate 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")@Beanpublic TestBean testBean2(){TestBean testBean = new TestBean();testBean.setName("java");testBean.toString();return testBean;}
}
4.2.6.3 Contoller
@RestController
public class TestController {@Autowiredprivate 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.hqwc.cn/news/529493.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

嘴尚绝卤味美味尽享

卤味&#xff0c;作为中国传统美食的代表之一&#xff0c;以其独特的口感和丰富的味道赢得了广大食客的喜爱。在众多卤味品牌中&#xff0c;嘴尚绝卤味凭借其安全可靠的品质和独特的美味&#xff0c;成为了消费者信赖的选择。 一、严格把控原材料&#xff0c;确保食品安全 嘴尚…

phpcms头像上传漏洞

经典版 漏洞原理&#xff1a;我们上传一个zip的压缩包&#xff0c;它会解压然后删除其中不是.jpg .gig .png的文件 function check_dir($dir)&#xff1a;这是一个PHP函数的定义&#xff0c;它接受一个参数 $dir&#xff0c;代表要检查的目录路径。 $handle opendir($dir);&…

响应式招标投标网站模板

模板信息&#xff1a; 模板编号&#xff1a;29165 模板编码&#xff1a;UTF8 模板分类&#xff1a;博客、文章、资讯、其他 适合行业&#xff1a;招标类企业 模板介绍&#xff1a; 下载转载自&#xff1a;https://www.qnziyw.cn/cmsmb/eyoucms/wenzhangzx/4332.html 本模板自带…

嵌入式开发系统学习——干货分享(一)

个人名片&#xff1a; &#x1f981;作者简介&#xff1a;学生 &#x1f42f;个人主页&#xff1a;妄北y &#x1f427;个人QQ&#xff1a;2061314755 &#x1f43b;个人邮箱&#xff1a;2061314755qq.com &#x1f989;个人WeChat&#xff1a;Vir2021GKBS &#x1f43c;本文由…

学c还行,学Python很累,还有其他语言适合我吗?

学c还行&#xff0c;学Python很累&#xff0c;还有其他语言适合我吗&#xff1f; 在开始前我分享下我的经历&#xff0c;我刚入行时遇到一个好公司和师父&#xff0c;给了我机会&#xff0c;一年时间从3k薪资涨到18k的&#xff0c; 我师父给了一些 电气工程师学习方法和资料&a…

【CSP试题回顾】202006-2-稀疏向量

CSP-202006-2-稀疏向量 关键点&#xff1a;时间复杂度 1.暴力枚举&#xff08;30分&#xff09; 在传统的暴力枚举方法中&#xff0c;我们有两个长度为 a 和 b 的稀疏向量&#xff0c;需要对这两个向量的全部元素逐一比较&#xff0c;如果 index 相等则进行乘积计算&#xf…

安卓studio安装

安卓studio安装 2024.3.11官网的版本&#xff08;有些翻墙步骤下载东西也解决了&#xff09; 这次写的略有草率&#xff0c;后面会更新布局的&#xff0c;因为截图量太大了&#xff0c;有需要的小伙伴可以试着接受一下哈哈哈哈 !(https://gitee.com/jiuzheyangbawjf/img/raw/ma…

亚马逊、速卖通卖家自养号测评细节需要掌握的哪几点?

亚马逊&#xff0c;跨境电商的巨头&#xff0c;早已成为业界的热门话题。如今&#xff0c;越来越多的卖家渴望在亚马逊的舞台上崭露头角&#xff0c;这也使得市场竞争愈发激烈。在亚马逊的丛林中&#xff0c;Review成为影响卖家命运的关键因素。它不仅影响亚马逊对卖家账号的评…

MySQL索引+常见问题详解

网络上的讲述MySQL索引的文章太多了&#xff0c;我打算换个角度来说。我们尝试着从设计者的角度思考&#xff0c;索引为什么这么设计。 假如你是索引的设计者&#xff0c;你会如何设计索引。我们不妨以新华字典为例。如果我们要查询汉字爱是什么意思&#xff0c;我们有如下操作…

Android电量/功耗优化指南

基础知识 电能 电压 * 电流 * 时长 模块电量(mAh) 模块电流(mA) * 时长(h) 系统电量优化红线规则 华为电量优化红线规则 电量分析 Android 系统电量计算 Android 系统的电量统计工作&#xff0c;是由一个叫 BatteryStatsService 的系统服务完成的。 其中四个比较关键的角…

C++的类与对象(五):赋值运算符重载与日期类的实现

目录 比较两个日期对象 运算符重载 赋值运算符重载 连续赋值 日期类的实现 Date.h文件 Date.cpp文件 Test.cpp文件 const成员 取地址及const取地址操作符重载 比较两个日期对象 问题描述&#xff1a;内置类型可直接用运算符比较&#xff0c;自定义类型的对象是多个…

卷积神经网络必备基础

卷积神经网络&#xff08;Convolutional Neural Network, CNN&#xff09; 传统的全连接神经网络并不适用于图像处理&#xff0c;这是因为&#xff1a;每个像素点都是一个输入特征&#xff0c;随着层数的增加&#xff0c;参数以指数级增长&#xff0c;而图片的像素点往往非常…