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