admin管理员组

文章数量:1599543

关历史文章(阅读本文前,您可能需要先看下之前的系列👇

国内最全的Spring Boot系列之四

享元模式:共享女友 - 第355篇

SpringBoot有没有学明白,就看你这些面试题是否懂?- 第389篇

Spring Boot CLI你知多少?- 第394篇

创建一个 Spring Boot 项目的4种方法,你会几种?- 第396篇

Spring Boot 项目中的 parent原来还有这么多的讲究 - 第398篇

Spring Boot条件注解 - 第400篇

>悟纤:师傅,条件注解实在太赞了,能避免很多重复在加载一些对象以及设置为一些开关在配置文件关闭一些不必要的加载。

>师傅:必须的好用,不然为师也不会告诉你了,来给个小费(伸手去要…)。

>悟纤:师傅我整个人都是你的了…

>师傅:徒儿… 这可是你说的哦… 那把你的银行卡给为师玩玩呗。

>悟纤:师傅,徒儿错了… 师傅,我发现一个小小的问题哦,我这里有一个需求,现在的条件注解不能满足我的需求耶,不知道怎么办了😰。

>师傅:O(∩_∩)O哈哈~ 这个时候吗,我们就需要自定义条件注解了,来这一篇咱们来好好聊聊。

>悟纤:(手舞足蹈)(。◕ˇ∀ˇ◕) 好开心耶~

       在前面的文章中《Spring Boot条件注解》,我们了解到了Spring Boot给我们提供了很多的条件注解,但是并不能满足所有的场景。

有这么一种需求可能就满足不了了:需要同一套代码适配个版本数据库(数据库不同,且部分表的字段及关联关系可能会不同)。

实现的关键点是对bean的实例化添加一个条件判断来控制。其实SpringBoot里面新增了很多条件注解,能实现这个功能。但是都有些局限性,最终是采用自定义条件注解的方案。

一、SpringBoot自带的注解ConditionalOnProperty

         这个注解不做过多的解释,只说通过这个注解怎么实现我们的功能。

假设我们application.properties中配置一个配置项为:

#bean实例化条件配置项
conditionKey=1.0

那么只需要加上@ConditionalOnProperty的name和havingValue就能实现,只有配置文件中name对应的配置项的值和havingValue内容一致才实例化这个对象。

针对我们上面配置的application.properties的内容,@ConditionalOnProperty的使用案例如下面代码所示:

@Component
@ConditionalOnProperty(name="conditionKey" ,havingValue = "1.0")
public class DAOAdapterImpl implements DAOAdapter{

    public void save(){
        System.out.println("我是实现类01");
    }

}

         这个注解的局限性:这个注解的havingValue里面只能配置一个值

    由于项目个性化需求,希望这个havingValue可以配置多个值,name对应的配置项的Value只要满足havingValue里面多个值的就表示匹配正确。即,havingValue里面可以配置多个值,name对应配置项的值来和havingValue匹配时,采用逻辑或匹配,满足一个值就算匹配正确。

二、自定义条件注解

2.1 思路

注解里面有2个属性,具体如下:

(1)name:String类型,用来接受application.properties的配置项的key

(2)havingValue:String数组类型,用来和name对应key的Value进行匹配

2.2 定义注解

         我们自定义注解:

import org.springframework.context.annotation.Conditional;
import java.lang.annotation.*;

/**
 * 自定义条件注解
 *
 * @author 悟纤「公众号SpringBoot」
 * @date 2021-10-12
 * @slogan 大道至简 悟在天成
 */

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
@Documented
@Conditional(CustomOnPropertyCondition.class)
public @interface CustomConditionalOnProperty {
    /**
     * 条件变量的name
     */
    String name() default "";
    /**
     * havingValue数组,支持or匹配
     */
    String[] havingValue() default {};
}

2.3 定义注解的匹配规则

         重点的实现就是匹配规则:

import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;
import java.util.Map;

/**
 * 自定义条件注解的验证规则
 *
 * @author 悟纤「公众号SpringBoot」
 * @date 2021-10-12
 * @slogan 大道至简 悟在天成
 */
public class CustomOnPropertyCondition implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        //获取注解上配置的信息
        Map<String, Object> annotationAttributes =  metadata.getAnnotationAttributes(CustomConditionalOnProperty.class.getName());
        String propertyName =  (String)annotationAttributes.get("name");
        String[] values = (String[]) annotationAttributes.get("havingValue");
        if (0 == values.length) {
            return false;
        }

        //获取环境中的配置的信息(这里也就是application.properties的信息)
        String propertyValue = context.getEnvironment().getProperty(propertyName);
        // 有一个匹配上就ok
        if(propertyValue != null){
            for (String havingValue : values) {
                if (havingValue.equalsIgnoreCase(propertyValue)) {
                    return true;
                }
            }
        }


        return false;
    }
}

2.4 使用

         使用起来是很简单的,如下示例:

@CustomConditionalOnProperty(name="conditionKey" ,havingValue = {"1.0","3.0"})

三、小结

自定义Condition注解,主要就2步:

(1)定义一个条件注解

(2)定义一个条件的校验规则

我就是我,是颜色不一样的烟火。
我就是我,是与众不同的小苹果。

à悟空学院:悟空学院

学院中有Spring Boot相关的课程!!

SpringBoot视频:从零开始学Spring Boot Plus - 网易云课堂

SpringBoot交流平台:https://t/R3QDhU0

SpringSecurity5.0视频:权限管理spring security - 网易云课堂

ShardingJDBC分库分表:分库分表Sharding-JDBC实战 - 网易云课堂

分布式事务解决方案:分布式事务解决方案「手写代码」 - 网易云课堂

JVM内存模型调优实战:深入理解JVM内存模型/调优实战 - 网易云课堂

Spring入门到精通:Spring零基础从入门到精通 - 网易云课堂

大话设计模式之爱你:大话设计模式之爱你一万年 - 网易云课堂

本文标签: 自定义注解实战SpringBootcondition