天天看點

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();
        }
    }
}           

繼續閱讀