前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >从零到一:SpringBoot自定义条件注解的创建与使用

从零到一:SpringBoot自定义条件注解的创建与使用

作者头像
索码理
发布2024-01-22 16:11:28
1760
发布2024-01-22 16:11:28
举报
文章被收录于专栏:索码理索码理

尽管未来似乎很遥远,但它实际上现在就开始了。

上篇文章《SpringBoot 条件注解一览无余》介绍了Springboot有哪些条件注解及一些属性的含义,本篇文章将介绍一下如何自定义条件注解。

话不多说,上代码。

实践出真知

先分析Springboot提供的注解

在自定义条件之前,咱先看看Springboot条件注解是怎么实现的,就挑 @ConditionalOnProperty 注解看一下。下图是@ConditionalOnProperty 注解的实现,从实现中可以看到除了元注解之外,它是被 @Conditional(OnPropertyCondition.class) 标记的,被@Conditional() 注解标记的注解表示该注解是个条件注解,@Conditional() 注解的value就对应着该注解的具体实现逻辑类。下面我们就主要看看 OnPropertyCondition 类是怎么实现的。

接下来我们将进行实操。

OnPropertyCondition 类继承了 SpringBootCondition 类,并重写了 getMatchOutcome() 方法,而 SpringBootCondition 类则是实现了 Condition接口并进行了封装,加入了类似日志之类的东西,感兴趣的可以细细看下,至此OnPropertyCondition 类就分析完了。

从上面的分析中我们可以发现,自定义条件注解主要分为两步:

  1. 自定义一个条件注解,该注解要被@Conditional() 注解标记。
  2. 写一个自定义条件注解的实现类。在实现时,有两个选择,一是继承 SpringBootCondition 类并重写 getMatchOutcome() 方法,二是实现 Condition接口并重写 matches() 方法。SpringBootConditionCondition接口的实现并进行了封装,推荐使用SpringBootCondition ,当然,如果自定义条件注解的实现类已经有父类,使用 Condition接口也是没问题的。

其实还有一种选择那就是实现 ConfigurationCondition ,它继承了Condition接口,并在其基础上增加了一些针对配置类的条件判断方法,使用它也可以实现自定义条件注解,下篇文章将介绍一下 ConfigurationCondition接口及其和Condition接口的区别。

OnPropertyCondition 类

SpringBootCondition

OnPropertyCondition类图

实操

众所周知,某练习两年半的练习生技能包里有唱跳、Rap、打篮球三项技能,下面就以该练习生技能包为案例,激活什么技能就用什么技能。

侵删

  1. 自定义条件注解

新建一个技能条件注解 ConditionalOnSkill ,里面就一个value属性

代码语言:javascript
复制
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(OnSkillCondition.class)
public @interface ConditionalOnSkill {

    /**
     * 技能
     * @return
     */
    String value();
}
  1. 自定义条件注解实现类

新建一个 技能条件注解实现类OnSkillCondition ,该类中定义一个 PROPERTY_NAME 常量,该常量的值最终会从配置文件中读取。

代码语言:javascript
复制
public class OnSkillCondition extends SpringBootCondition {

    private static final String PROPERTY_NAME = "brother-rooster.skill";

    @Override
    public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
        //获取所有被自定义条件注解标记的填写的属性值
        Map<String, Object> attributes = metadata.getAnnotationAttributes(ConditionalOnSkill.class.getName());
        //获取常量值
        String value = attributes.get("value").toString();
        Environment environment = context.getEnvironment();
        //读取PROPERTY_NAME值
        String property = environment.getProperty(PROPERTY_NAME);

        ConditionMessage.Builder message = ConditionMessage.forCondition(ConditionalOnSkill.class);
        ConditionMessage conditionMessage = message.foundExactly(value);
        boolean match = value.equals(property);
        return new ConditionOutcome(match, conditionMessage);
    }
}
  1. 创建Bean接口及实现类

创建一个BrotherRoosterSkill接口,用于测试条件注解,然后分别创建3个实现类:篮球技能BrotherRoosterSkillBasketball、rap技能 BrotherRoosterRap、唱跳技能 BrotherRoosterSkillSing

代码语言:javascript
复制
public interface BrotherRoosterSkill {

    void printSkill();

}
代码语言:javascript
复制
public class BrotherRoosterSkillBasketball implements BrotherRoosterSkill {
    @Override
    public void printSkill() {
        System.out.println("打篮球");
    }
}
代码语言:javascript
复制
public class BrotherRoosterRap implements BrotherRoosterSkill {
    @Override
    public void printSkill() {
        System.out.println("rap");
    }
}
代码语言:javascript
复制
public class BrotherRoosterSkillSing implements BrotherRoosterSkill{
    @Override
    public void printSkill() {
        System.out.println("唱跳");
    }
}
  1. 新建配置注入技能包的Bean 创建 ConditionConfig配置类 注入技能Bean
代码语言:javascript
复制
@Component
public class ConditionConfig {

    @Bean("brotherRoosterSkill")
    @ConditionalOnSkill("basketball")
    BrotherRoosterSkill brotherRoosterSkillBasketball(){
        System.out.println("打篮球技能激活。。。。。");
        return new BrotherRoosterSkillBasketball();
    }

    @Bean("brotherRoosterSkill")
    @ConditionalOnSkill("rap")
    BrotherRoosterSkill brotherRoosterSkillRap(){
        System.out.println("Rap技能激活。。。。。");
        return new BrotherRoosterRap();
    }

    @Bean("brotherRoosterSkill")
    @ConditionalOnSkill("sing")
    BrotherRoosterSkill brotherRoosterSkillSing(){
        System.out.println("唱跳技能激活。。。。。");
        return new BrotherRoosterSkillSing();
    }
}
  1. 测试

在配置文件中加入如下配置:

代码语言:javascript
复制
#kk技能包
brother-rooster.skill=sing

写一个单元测试类:

代码语言:javascript
复制
@SpringBootTest
public class ConditionalTest {

    @Resource
    private BrotherRoosterSkill brotherRoosterSkill;

    @Test
    public void testBrotherRoosterSkill(){
        System.out.println("鸡哥激活了哪个技能包:");
        brotherRoosterSkill.printSkill();
    }
}

启动测试,控制台打印结果如下图所示,可以看到 BrotherRoosterSkillSing被实例化了。

把配置改成 brother-rooster.skill=basketball , 控制台打印结果如下图所示,可以看到 BrotherRoosterSkillBasketball被实例化了。

至此,一个简单的Springboot自定义条件注解就搞定了。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2024-01-19,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 索码理 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 实践出真知
    • 先分析Springboot提供的注解
      • 实操
      相关产品与服务
      腾讯云服务器利旧
      云服务器(Cloud Virtual Machine,CVM)提供安全可靠的弹性计算服务。 您可以实时扩展或缩减计算资源,适应变化的业务需求,并只需按实际使用的资源计费。使用 CVM 可以极大降低您的软硬件采购成本,简化 IT 运维工作。
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档