实现自定义conditional注解

存在这样一个需求,引入了xx类后,就创建A类型bean对象,否则创建B类型bean对象。
我们先来做一个简单的实现

static class MyCondition1 implements Condition { // 存在 Druid 依赖
        @Override
        public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
            return ClassUtils.isPresent("com.alibaba.druid.pool.DruidDataSource", null);
        }
    }

    static class MyCondition2 implements Condition { // 不存在 Druid 依赖
        @Override
        public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
            return !ClassUtils.isPresent("com.alibaba.druid.pool.DruidDataSource", null);
        }
    }

    @Configuration // 第三方的配置类
    @Conditional(MyCondition1.class)
    static class AutoConfiguration1 {
        @Bean
        public Bean1 bean1() {
            return new Bean1();
        }
    }

    @Configuration // 第三方的配置类
    @Conditional(MyCondition2.class)
    static class AutoConfiguration2 {
        @Bean
        public Bean2 bean2() {
            return new Bean2();
        }
    }

在上述实现中,MyCondition1,MyCondition2实现了Condition接口的matches方法,并作为参数传递给@Conditional注解,当系统中引入了"com.alibaba.druid.pool.DruidDataSource"类后,MyCondition1的判断为true,AutoConfiguration1被加载,bean1被创建。
上述实现符合我们的需求,但它有两个明显的问题:
(1)直接固定了xx类的名字为"com.alibaba.druid.pool.DruidDataSource"
(2)MyCondition1,MyCondition2的条件很像,却写了两个类。

针对这两个问题,我们做下改造。
首先我们在MyCondition中加入判断条件exists,使得MyCondition能兼顾MyCondition1和MyCondition2的功能,
className参数使得MyCondition可以支持对不同的类进行判断。

    static class MyCondition implements Condition { // 存在 Druid 依赖
        @Override
        public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
            Map<String, Object> attributes = metadata.getAnnotationAttributes(ConditionalOnClass.class.getName());
            String className = attributes.get("className").toString();
            boolean exists = (boolean) attributes.get("exists");
            boolean present = ClassUtils.isPresent(className, null);
            return exists ? present : !present;
        }
    }

由于@Conditional只支持一个参数,所以我们要实现新的注解来支持exists参数。在这里插入图片描述

@Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.METHOD, ElementType.TYPE})
    @Conditional(MyCondition.class)
    @interface ConditionalOnClass {
        boolean exists(); // true 判断存在 false 判断不存在

        String className(); // 要判断的类名
    }

在ConditionalOnClass注解中,支持传入className和exists参数。
这两个参数最终会被MyCondition的match方法读取到,从而实现根据类名进行判断的功能。
改造的使用示例为:

 @Configuration // 第三方的配置类
    @ConditionalOnClass(className = "com.alibaba.druid.pool.DruidDataSource", exists = false)
    static class AutoConfiguration1 {
        @Bean
        public Bean1 bean1() {
            return new Bean1();
        }
    }

    @Configuration // 第三方的配置类
    @ConditionalOnClass(className = "com.alibaba.druid.pool.DruidDataSource", exists = true)
    static class AutoConfiguration2 {
        @Bean
        public Bean2 bean2() {
            return new Bean2();
        }
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值