首页 > 其他分享 > Springboot Condition 实用讲解,只看一遍包学会

Springboot Condition 实用讲解,只看一遍包学会

时间:2023-03-02 15:15:29浏览次数:60  
标签:Springboot app 看一遍 Dragon bean 实例 import public Condition

前言

 

该篇文章,还是一贯的风格,源码+示例+自言自语的分析,目的只有一个 :

就是想让大家都会玩 Condition、Conditional。

 

 

 

正文

先看看 Condition 是被放在包spring context(上下文/容器) 里面了:

spring context(上下文/容器)

 

接着我们看看作者写的 Condition 源码: 

ps: 学东西,一定要看看源码,往往作者留下的注释比你自己千方百计找的解释都好,当然你找到我这边的文章,另当别论(别当真)。

 大致意思我给各位看官简述一下:

 利用 Condition ,在一个bean快被注册前, 我们可以根据任何的自由标准,立即触发条件的检查 ,使用 matches方法去 决定 是否注册。

看完注释,继续看下代码:

1.   这是一个 interface,意味着可以实现,然后重写里面的方法函数。

2.   可以看到里面只有一个mathes(匹对)方法 ,boolean类型返回值 ,

      意思比较明确易懂,就是匹对 成功了,就是 符合条件;  反之,则反之。  


然后看到还有@Conditional注解,这就是配套使用的,我们立刻进入示例实战,看看怎么用。

 

模拟一个场景:
 

一个实体类Dragon 神龙 ,我们需要创建这个bean,但是有条件。
  
这个bean被创建的条件是,
通过配置项可以得知当前项目7颗龙珠是否收集完了,只有收集到7颗才能召唤神龙。

 

我们先建实体类 Dragon.java :
 

  1.   /**
  2.   * @Author JCccc
  3.   * @Description
  4.   * @Date 2021/08/11 9:55
  5.   */
  6.   public class Dragon {
  7.    
  8.   private String name;
  9.   private Integer age;
  10.   private String master = "JCccc";
  11.    
  12.    
  13.    
  14.   public Dragon(String name, Integer age) {
  15.   this.name = name;
  16.   this.age = age;
  17.   }
  18.    
  19.   @Override
  20.   public String toString() {
  21.   return "Dragon{" +
  22.   "name='" + name + '\'' +
  23.   ", age=" + age +
  24.   ", master='" + master + '\'' +
  25.   '}';
  26.   }
  27.   }

然后在MyBeanConfig.java 里面把这个bean创建丢到容器里:
 

  1.   import org.springframework.context.annotation.Bean;
  2.   import org.springframework.context.annotation.Conditional;
  3.   import org.springframework.context.annotation.Configuration;
  4.    
  5.   /**
  6.   * @Author JCccc
  7.   * @Description
  8.   * @Date 2021/10/19 10:01
  9.   */
  10.   @Configuration
  11.   public class MyBeanConfig {
  12.    
  13.   @Bean
  14.   @Conditional(DragonCondition.class)
  15.   public Dragon createDragon() {
  16.   return new Dragon("波伦加",18);
  17.   }
  18.    
  19.    
  20.   }

 

可以看到,我这创建bean,使用了 @Conditional :

@Conditional(DragonCondition.class)

没错,这就是我给 这个Dragon实体类 自定义的创建前置条件 ,DragonCondition :
 

ps: DragonCondition 实现了 Condition接口, 然后重写了匹对方法mathces,写了一些判断逻辑,从配置文件中取值,看看龙珠颗数是否为7。

  1.   import org.springframework.context.annotation.Condition;
  2.   import org.springframework.context.annotation.ConditionContext;
  3.   import org.springframework.core.type.AnnotatedTypeMetadata;
  4.    
  5.   import java.util.Objects;
  6.    
  7.   /**
  8.   * @Author JCccc
  9.   * @Description 召唤神龙的条件
  10.   * @Date 2021/10/19 10:03
  11.   */
  12.   public class DragonCondition implements Condition {
  13.   @Override
  14.   public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
  15.    
  16.   if (7 == Integer.parseInt(Objects.requireNonNull(context.getEnvironment().getProperty("summon.dragon-ball")))){
  17.   return true;
  18.   }
  19.    
  20.   return false;
  21.   }
  22.   }

接下来,我们来测试一下,

我们在yml文件添加配置项:
 

summon:
  dragon-ball: 7

然后到测试类里面简单写个测试方法,看看Dragon 这个bean是否能成功被创建 :

 

  1.   import com.elegant.testdemo.happy.Dragon;
  2.   import org.junit.jupiter.api.Test;
  3.   import org.springframework.beans.factory.annotation.Autowired;
  4.   import org.springframework.boot.test.context.SpringBootTest;
  5.    
  6.    
  7.    
  8.   @SpringBootTest
  9.   class TestdemoApplicationTests {
  10.    
  11.   @Autowired(required = false)
  12.   //Autowired 设置为false,允许注入的时候找不到的情况,不会报错
  13.   private Dragon dragon;
  14.    
  15.   @Test
  16.   void contextLoads() {
  17.    
  18.   System.out.println(dragon);
  19.    
  20.   }
  21.    
  22.   }

执行,可以看到,因为我们条件匹对符合,神龙bean能成功创建:

 那么我们把配置里面的龙珠颗树参数改一下,改成 5 :

 

到这里,其实 基本的Condition 配合 @Conditional 注解的使用已经掌握了。


那么接下来,继续,我们开始玩一下这个派生注解:

 

@ConditionalOnBean:当容器中有指定Bean的条件下进行实例化。
@ConditionalOnMissingBean:当容器里没有指定Bean的条件下进行实例化。
@ConditionalOnClass:当classpath类路径下有指定类的条件下进行实例化。
@ConditionalOnMissingClass:当类路径下没有指定类的条件下进行实例化。
@ConditionalOnWebApplication:当项目是一个Web项目时进行实例化。
@ConditionalOnNotWebApplication:当项目不是一个Web项目时进行实例化。
@ConditionalOnProperty:当指定的属性有指定的值时进行实例化。
@ConditionalOnExpression:基于SpEL表达式的条件判断。
@ConditionalOnJava:当JVM版本为指定的版本范围时触发实例化。
@ConditionalOnResource:当类路径下有指定的资源时触发实例化。
@ConditionalOnJndi:在JNDI存在的条件下触发实例化。
@ConditionalOnSingleCandidate:当指定的Bean在容器中只有一个,或者有多个但是指定了首选的Bean时触发实例化。

 


接下来我挑选几个常用的细细说说,

 

@ConditionalOnProperty : 当指定的属性有指定的值时进行实例化。

也就是说,我们可以让某个bean创建时,进行 配置值的匹对,符合条件了才能正常创建。

 

实践环节

 

单值匹对

示例:

RoleInitializer 这个bean,如果想让它正常实例化,我们需要检测yml配置文件里面,app.public的值是否为 true :

 yml配置文件我们添加配置值:

 启动项目,可以看到这个bean是符合条件的成功实例化:

 我们把yml的值改一下:

再启动项目,可以看到这个bean没有被实例化,因为不符合条件:
 

 ps:到这,也许会有一些看官会有想法:

这样的使用注解去检测yml里面的值,跟我们直接拉去配置文件的值,写个if判断 不是一样吗?

答案: 看似一样,实则并不。 硬编码的概念。 实例化和没实例化的区别。 不多说。


还没完, 上面是 @ConditionalOnProperty比较简单的使用例子,单纯一个配置值的匹对。

接下来是多值匹对场景

示例 :

RoleInitializer 这个bean,如果想让它正常实例化,我们需要检测yml配置文件里面,app.public的值是否为 true 且 app.vip 的值 也为 true:

关系是 且 ,也就是AND ,同时符合的概念,我们可以这么写:

@ConditionalOnProperty(name={"app.public","app.vip"}, havingValue="true")


@ConditionalOnProperty的注解能够支撑的、常用的方式也就差不多这些,更多元化的匹对效果是无法支持的,例如我们想要 匹对条件值A 为 1 同时 B 为  2 ,这种情形就已经无法支撑了。
不过我们可以换个概念表达,变成 匹对条件值AB 为 12 .

而且再补充一点,目前@ConditionalOnProperty的使用都是 且 (AND) 关系,如果你要用OR的方式的条件,那么也是很 sorry,@ConditionalOnProperty 支撑不了。


除非我们使用文章一开始介绍的自定义condition,完全是ok的。

 

那么就只能用自定义condition去实现这些多条件的匹对场景了吗? 

 

答案是 : 并不 ,接下来看@ConditionalOnExpression 注解。

 

@ConditionalOnExpression :基于SpEL表达式的条件判断。

也是可以用于对配置文件的属性做一些匹对条件,但是功能强大很多。

 

就基于上面说到的例子,我们如果需要匹对的条件是多值:


app.public 值为 true  且 app.vip 值为 high 时 ,才能正常实例化RoleInitializer这个bean。

那么使用@ConditionalOnExpression ,我们可以这么写:

@ConditionalOnExpression("'${app.vip}'.equals('high')&&${app.public:true}")
 

从这,引申出一些 用法 的介绍:

如果我们想匹配的配置项的值 是字符串类型 ,我们写法是:
 

@ConditionalOnExpression("'${app.public}'.equals('JC')")

如果是 数字类型 ,我们写法是:
 

@ConditionalOnExpression("${app.public}==18")

如果是 布尔类型 ,我们写法是:

@ConditionalOnExpression("${app.public:true}")

 

那么还有 与 关系 写法,使用  && :

@ConditionalOnExpression("'${app.vip}'.equals('high')&&${app.public:true}")

或 关系 写法,使用  || :

@ConditionalOnExpression("${app.public:true} || ${app.vip:true}")

 

继续下一个 ,

@ConditionalOnMissingBean:当容器里没有指定Bean的条件下进行实例化。

 

基于文章一开始的 Dargon示例我们继续 使用一下这个注解,

 

模拟场景:

 如果  Dargon 神龙没有符合条件实例化成功,那么我们自动召唤 阿拉丁神灯 作为备用。

 

 DragonCondition 自定义的实例化条件,回顾一下:

 现在故意把yml的神龙召唤配置值改成 不符合条件的数值:

写个测试方法,执行一下:

结果跟我们要的是一样的:

 

我们反之再把相关的配置改成,符合 Dragon bean创建的的条件,这么一来,MagicLamp肯定就是不用创建出来了: 

 

@ConditionalOnBean:当容器中有指定Bean的条件下进行实例化。

这个在我们刚才尝试过 OnMissingBean的使用后,我认为我们应该不需要看示例了。

也就是指定某个bean在实例化的前提 必须是 指定的bean先实例化之后才能实例化。

 

 

好了,该篇就暂时这么样吧。有问题,随时留言交流 。   点赞+1 ,收藏+1,关注+1

 

 

https://blog.csdn.net/qq_35387940/article/details/120839504

 

 

   

标签:Springboot,app,看一遍,Dragon,bean,实例,import,public,Condition
From: https://www.cnblogs.com/tiancai/p/17171779.html

相关文章

  • SpringBoot+MybatisPlus+MySql 自动生成代码 自动分页
    SpringBoot+MybatisPlus+MySql自动生成代码自动分页一、配置<!--Mybatisplus--><dependency><groupId>com.baomidou</groupId>......
  • Xmemcached与SpringBoot实际案例
    在本人的这篇文章《​​Xmemcached集群与SpringBoot整合​​》基础上,进行XMemcached与SpringBoot实际案例的结合。有以下这张表,将这张表的增删改查操作都添加到XMemcached中......
  • springboot后端接收不到前端传来的表单值
    为啥接收不到因为传来的字段值太大了,springboot默认启动依赖tomcat,tomcat默认接收表单值最大为2MB,将server.tomcat.max-http-form-post-size这个配置调大即可#yml方式s......
  • SpringBoot+WebSocket实现实时获取系统数据
    SpringBoot+WebSocket实现实时获取系统数据引入maven依赖<dependencies><dependency><groupId>org.springframework.boot</groupId>......
  • SpringBoot——常用配置
    application.yml配置信息spring:profiles:active:devapplication:name:jwt-token-security#Jackson配置项jackson:serialization:......
  • SpringBoot自定义启动时的ASCII艺术字
    1.SpringBoot默认的艺术字2.进入ASCII艺术字网站https://www.bootschool.net/ascii3.把下载的banner.txt文件放在resource目录4.重新启动项目【注意:如果不生效的......
  • SpringBoot
    简介SprintBoot是一款快速开发框架,能够帮助我们快速整合第三方框架不同于SSM项目繁琐的xml配置,SpintBoot去除了xml配置全部采用注解化的方式配置内嵌Tomcat,运行就会启......
  • SpringBoot过滤器获取请求Body
    packagecom.example.springboot.core;importlombok.extern.slf4j.Slf4j;importorg.springframework.stereotype.Component;importjavax.servlet.http.HttpServle......
  • SpringBoot自定义拦截器和跨域配置冲突的问题
    跨域配置完成以后,又进行拦截器的配置,发现跨域配置失效,以下是原配置@ConfigurationpublicclassCORSConfigimplementsWebMvcConfigurer{@BeanpublicWebMv......
  • SpringBoot Actuator RCE 漏洞总结
    一、SpringBootenv获取*敏感信息 当我们直接访问springboot站点时,可以看到某些password字段填充了*通过${name}可以获取明文字段  2.配置不当导致敏感信息......