天天看点

springboot(三十八)springboot自定义Condtional注解

作者:聪明的晚风zqw

@Condtional注解在Spring4中引入,其主要作用就是判断条件是否满足,从而决定是否初始化并向容器注册Bean

以下是spring中的一些Conditional:

@ConditionalOnJava 系统的java版本是否符合要求

@ConditionalOnBean 容器中存在指定Bean;

@ConditionalOnMissingBean 容器中不存在指定Bean;

@ConditionalOnExpression 满足SpEL表达式指定

@ConditionalOnClass 系统中有指定的类

@ConditionalOnMissingClass 系统中没有指定的类

@ConditionalOnSingleCandidate 容器中只有一个指定的Bean,或者这个Bean是首选Bean

@ConditionalOnProperty 系统中指定的属性是否有指定的值

@ConditionalOnResource 类路径下是否存在指定资源文件

@ConditionalOnWebApplication 当前是web环境

@ConditionalOnNotWebApplication 当前不是web环境

@ConditionalOnJndi JNDI存在指定项

用户可以自定义Conditonal扩展注解,其内部主要就是利用了Condition接口,来判断是否满足条件,从而决定是否需要加载Bean。

下面测试自定义一个@ConditionalOnElasticJob注解以判断是否启用了elasticJob,启用的情况下才会加载某些Bean

**elasticJob是分布式定时任务,可以理解为一个功能,不是此文章讨论的重点。

1、已经自定义了ElasticJob的开关注解

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(ElasticJobConfig.class)
public @interface EnableElasticJob {
}           

此注解无法完全满足ElasticJob开关是因为此注解控制了ElasticJobConfig类的配置开关,但@Component、@Service等注解修饰的ElasticJob相关功能的类无法开关。

2、自定义@ConditionalOnElasticJob注解

package com.iscas.base.biz.config.elasticjob;

import org.springframework.context.annotation.Conditional;

import java.lang.annotation.*;

/**
 *
 * @author zhuquanwen
 * @vesion 1.0
 * @date 2021/4/1 9:39
 * @since jdk1.8
 * */

 @Target({ ElementType.TYPE, ElementType.METHOD })
 @Retention(RetentionPolicy.RUNTIME)
 @Documented
 @Conditional(OnElasticJob.class)
public @interface ConditionalOnElasticJob {
}           

3、OnElasticJob类做判断

通过读取EnableElasticJob注解,如果能读到,证明已经开启了ElasticJob功能

package com.iscas.base.biz.config.elasticjob;

import com.iscas.base.biz.aop.enable.EnableElasticJob;
import org.apache.commons.collections4.MapUtils;
import org.springframework.boot.autoconfigure.condition.ConditionMessage;
import org.springframework.boot.autoconfigure.condition.ConditionOutcome;
import org.springframework.boot.autoconfigure.condition.SpringBootCondition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.core.type.AnnotatedTypeMetadata;

import java.util.Map;

/**
 *
 * @author zhuquanwen
 * @vesion 1.0
 * @date 2021/4/1 9:41
 * @since jdk1.8
 */
@Order(Ordered.HIGHEST_PRECEDENCE + 20)
public class OnElasticJob extends SpringBootCondition {
    @Override
    public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
        ConditionMessage.Builder message = ConditionMessage.forCondition("");
        Map<String, Object> beansWithAnnotation = context.getBeanFactory().getBeansWithAnnotation(EnableElasticJob.class);
        boolean match = MapUtils.isNotEmpty(beansWithAnnotation);
        return match ? ConditionOutcome.match(message.foundExactly("EnableElaticJob")) :
                ConditionOutcome.noMatch(message.because("not EnableElaticJob"));
    }
}           

4、在某些@Component的类上加上@ConditionalOnElasticJob注解

例如ElasticJobHandler

此类只有主类上添加@EnableElasticJob后才会注入Spring。如果不添加

ConditionalOnElasticJob注解,无法对@Component修饰的类做开关控制。

注意的是Spring中@ConditionalOnBean注解经过测试无法达到控制的目的,

因为@Component注解的加载要比@Configuration修饰的类早。

package com.iscas.base.biz.config.elasticjob;


import com.dangdang.ddframe.job.api.simple.SimpleJob;
import com.dangdang.ddframe.job.config.JobCoreConfiguration;
import com.dangdang.ddframe.job.config.simple.SimpleJobConfiguration;
import com.dangdang.ddframe.job.event.JobEventConfiguration;
import com.dangdang.ddframe.job.lite.api.listener.ElasticJobListener;
import com.dangdang.ddframe.job.lite.config.LiteJobConfiguration;
import com.dangdang.ddframe.job.lite.spring.api.SpringJobScheduler;
import com.dangdang.ddframe.job.reg.zookeeper.ZookeeperRegistryCenter;
import com.iscas.base.biz.service.common.SpringService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * elasticJob处理类
 *
 * @author zhuquanwen
 * @vesion 1.0
 * @date 2021/3/26 14:28
 * @since jdk1.8
 */
@ConditionalOnElasticJob()
@Component
public class ElasticJobHandler {

    @Autowired
    private ZookeeperRegistryCenter zookeeperRegistryCenter;


    @Autowired
    private ElasticJobListener elasticJobListener;
    @Autowired(required = false)
    private JobEventConfiguration jobEventConfiguration;

    /**
     * @param jobName
     * @param jobClass
     * @param shardingTotalCount
     * @param cron
     * @param jobParameter  参数
     * @param shardingItemParameters 分片数据
     * @return
     */
    private static LiteJobConfiguration.Builder simpleJobConfigBuilder(String jobName,
                                                                       Class<? extends SimpleJob> jobClass,
                                                                       int shardingTotalCount,
                                                                       String cron,
                                                                       String jobParameter,
                                                                       String shardingItemParameters) {
        return LiteJobConfiguration.newBuilder(new SimpleJobConfiguration(
                JobCoreConfiguration.newBuilder(jobName, cron, shardingTotalCount).shardingItemParameters(shardingItemParameters)
                        .jobParameter(jobParameter).build(), jobClass.getCanonicalName()));
    }

    /**
     * 添加一个定时任务
     *
     * @param jobName            任务名
     * @param cron               表达式
     * @param shardingTotalCount 分片数
     */
    public void addJob(String jobName, String cron, Integer shardingTotalCount, String jobParameter, String shardingItemParameters, Class<? extends SimpleJob> clazz) {
        LiteJobConfiguration jobConfig = simpleJobConfigBuilder(jobName, clazz, shardingTotalCount, cron, jobParameter, shardingItemParameters)
                .overwrite(true).build();
        if (jobEventConfiguration == null) {
            new SpringJobScheduler(SpringService.getBean(clazz), zookeeperRegistryCenter, jobConfig, elasticJobListener).init();
        } else {
            new SpringJobScheduler(SpringService.getBean(clazz), zookeeperRegistryCenter, jobConfig, jobEventConfiguration, elasticJobListener).init();
        }
    }
}           

继续阅读