015 springboot自动装配(中台:ElasticJob基础组件封装案例)

mac2024-03-06  33

        spring在进行扩展的时候,最常用的就是@Autowired 自动装配或Module-wired模块装配(@EnableXXX),Module-wired是将模块整体引入工程中,然后通过几个自定义注解完成应用;

step1. 创建springboot工程rabbit-task引入依赖pom.xml

<properties> <java.version>1.8</java.version> <elastic-job.version>2.1.4</elastic-job.version> </properties> <dependencies> <!-- spring boot dependency --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <!-- elastic-job dependency --> <dependency> <groupId>com.dangdang</groupId> <artifactId>elastic-job-lite-core</artifactId> <version>${elastic-job.version}</version> </dependency> <dependency> <groupId>com.dangdang</groupId> <artifactId>elastic-job-lite-spring</artifactId> <version>${elastic-job.version}</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> <optional>true</optional> </dependency> </dependencies>

step2. 创建JobParserAutoConfigure自动装配类

import org.springframework.context.annotation.Configuration; @Configuration public class JobParserAutoConfigure { }

step3. 创建spring.fatories自动装配加载文件

# Auto Configure org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.cc.rabbit.task.autoconfigure.JobParserAutoConfigure

        如此rabbit-task构建完成后,引入其他工程时,就会自动找到spring.fatories文件,并将由@Configuration声明的JobParserAutoConfigure做相关的初始化或其他操作,此装配为无条件默认装配。

step4. 通过@Conditional做条件装配:常用@ConditionalOnProperty()进行条件设置,其条件代表需要在application.properties或*.properties文件中配置规定的参数,才启动装配;

通过elastic-job配置来举个例子,elastic-job的使用需要依赖zookeeper配置,将namespace、serverLists作为必须配置参数作为装配条件,同时也是构造条件(官方API设定),其他配置项通过JobZookeeperProperties类进行封装,传入ZookeeperRegistryCenter完成注册中心初始化:

import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import com.dangdang.ddframe.job.reg.zookeeper.ZookeeperConfiguration; import com.dangdang.ddframe.job.reg.zookeeper.ZookeeperRegistryCenter; /** * @ConditionalOnProperty(prefix = "elastic.job.zk", name = {"namespace","serverLists"},matchIfMissing = false) * 引入rabbit-task的工程必须在application.properties中配置elastic.job.zk.namespace和 * elastic.job.zk.serverLists两个属性,才会装配成功,matchIfMissing = false如果没有配置两个参数 * 那么rabbit-task就不会加载,此处为强约定; * @EnableConfigurationProperties(JobZookeeperProperties.class),当@ConditionalOnProperty验证通过后,将elastic.job.zk * 为前缀的配置参数读到JobZookeeperProperties中;然后初始化registryCenter。 */ @Configuration @ConditionalOnProperty(prefix = "elastic.job.zk", name = {"namespace","serverLists"},matchIfMissing = false) @EnableConfigurationProperties(JobZookeeperProperties.class) public class JobParserAutoConfigure { //初始化RegistryCenter @Bean(initMethod = "init") public ZookeeperRegistryCenter zookeeperRegistryCenter(JobZookeeperProperties jobZookeeperProperties) {//如果将ZookeeperRegistryCenter注入到spring容器,那么Bean的名字就是方法名字(约定) ZookeeperConfiguration zkConfig = new ZookeeperConfiguration(jobZookeeperProperties.getServerLists(), jobZookeeperProperties.getNamespace()); zkConfig.setBaseSleepTimeMilliseconds(zkConfig.getBaseSleepTimeMilliseconds()); zkConfig.setMaxSleepTimeMilliseconds(zkConfig.getMaxSleepTimeMilliseconds()); zkConfig.setConnectionTimeoutMilliseconds(zkConfig.getConnectionTimeoutMilliseconds()); zkConfig.setSessionTimeoutMilliseconds(zkConfig.getSessionTimeoutMilliseconds()); zkConfig.setMaxRetries(zkConfig.getMaxRetries()); zkConfig.setDigest(zkConfig.getDigest()); System.out.println("初始化job注册中心配置成功"+zkConfig.getNamespace()); return new ZookeeperRegistryCenter(zkConfig); } } import org.springframework.boot.context.properties.ConfigurationProperties; import lombok.Data; /** * 装载配置参数 * 装载任何封装组件属性参数时,都要参考官方进行对应,必要配置项扫描加载, * 非必要配置项要设定默认值,范围要根据官方给定的有效范围进行设定; * 必要配置与非必要配置区分,其一根据业务设定,其二官方在属性说明中 * 会有是否为构造器注入,是就为必要配置,否即为非必要配置。 */ @Data @ConfigurationProperties(prefix = "elastic.job.zk") public class JobZookeeperProperties { private String namespace; private String serverLists; private int maxRetries = 3; private int connectionTimeoutMilliseconds = 15000; private int sessionTimeoutMilliseconds = 60000; private int baseSleepTimeMilliseconds = 1000; private int maxSleepTimeMilliseconds = 3000; private String digest = ""; }

step5. 自定义模块装配注解@EnableElasticJob:模块装配注解,除了自定义注解的四个基本属性,还必须要使用@Import注解,将自定义的配置类JobParserAutoConfigure引入;

package com.cc.rabbit.task.annotation; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Inherited; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import org.springframework.context.annotation.Import; import com.cc.rabbit.task.autoconfigure.JobParserAutoConfigure; /** * 1 注解四个基本属性设置; * 2 模块注入注解:@Import(JobParserAutoConfigure.class) */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @Import(JobParserAutoConfigure.class) public @interface EnableElasticJob { }

step6. 自定义@ElasticJobConfig,进行es-job的基础API参数构建,规避每次创建任务都需要构建job类,实现注解式配置,当需要一个job,那么按照此配置项加载一个类,自动解析;

package com.cc.rabbit.task.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * 封装elasticjob官方属性,依据官方api给出的属性参数进行声明; */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface ElasticJobConfig { /*JobCoreConfiguration属性详细说明*/ String jobName(); //elasticjob的名称 String cron() default ""; int shardingTotalCount() default 1; String shardingItemParameters() default ""; String jobParameter() default ""; boolean failover() default false; boolean misfire() default true; String description() default ""; /*DataflowJobConfiguration属性详细说明---是否流式处理数据*/ boolean streamingProcess() default false; /*ScriptJobConfiguration属性详细说明---脚本型作业*/ String scriptCommandLine() default ""; /*LiteJobConfiguration属性详细说明---作业运行监控配置*/ boolean monitorExecution() default false; public int monitorPort() default -1; //must public int maxTimeDiffSeconds() default -1; //must public String jobShardingStrategyClass() default ""; //must public int reconcileIntervalMinutes() default 10; //must public String eventTraceRdbDataSource() default ""; //must /*job:simple命名空间属性详细说明*/ public boolean disabled() default false; //must boolean overwrite() default false; public String distributedListener() default ""; public long startedTimeoutMilliseconds() default Long.MAX_VALUE; //must public long completedTimeoutMilliseconds() default Long.MAX_VALUE; //must public String jobExceptionHandler() default "com.dangdang.ddframe.job.executor.handler.impl.DefaultJobExceptionHandler"; public String executorServiceHandler() default "com.dangdang.ddframe.job.executor.handler.impl.DefaultExecutorServiceHandler"; }

step7. 解析自定义@ElasticJobConfig:JobParserAutoConfigure中创建ElasticJobConfParser来解析注解;

package com.cc.rabbit.task.autoconfigure; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import com.cc.rabbit.task.parser.ElasticJobConfParser; import com.dangdang.ddframe.job.reg.zookeeper.ZookeeperConfiguration; import com.dangdang.ddframe.job.reg.zookeeper.ZookeeperRegistryCenter; /** * @ConditionalOnProperty(prefix = "elastic.job.zk", name = {"namespace","serverLists"},matchIfMissing = false) * 引入rabbit-task的工程必须在application.properties中配置elastic.job.zk.namespace和 * elastic.job.zk.serverLists两个属性,才会装配成功,matchIfMissing = false如果没有配置两个参数 * 那么rabbit-task就不会加载,此处为强约定; * @EnableConfigurationProperties(JobZookeeperProperties.class),当@ConditionalOnProperty验证通过后,将elastic.job.zk * 为前缀的配置参数读到JobZookeeperProperties中;然后初始化registryCenter。 */ @Configuration @ConditionalOnProperty(prefix = "elastic.job.zk", name = {"namespace","serverLists"},matchIfMissing = false) @EnableConfigurationProperties(JobZookeeperProperties.class) public class JobParserAutoConfigure { //初始化RegistryCenter @Bean(initMethod = "init") public ZookeeperRegistryCenter zookeeperRegistryCenter(JobZookeeperProperties jobZookeeperProperties) {//如果将ZookeeperRegistryCenter注入到spring容器,那么Bean的名字就是方法名字(约定) ZookeeperConfiguration zkConfig = new ZookeeperConfiguration(jobZookeeperProperties.getServerLists(), jobZookeeperProperties.getNamespace()); zkConfig.setBaseSleepTimeMilliseconds(zkConfig.getBaseSleepTimeMilliseconds()); zkConfig.setMaxSleepTimeMilliseconds(zkConfig.getMaxSleepTimeMilliseconds()); zkConfig.setConnectionTimeoutMilliseconds(zkConfig.getConnectionTimeoutMilliseconds()); zkConfig.setSessionTimeoutMilliseconds(zkConfig.getSessionTimeoutMilliseconds()); zkConfig.setMaxRetries(zkConfig.getMaxRetries()); zkConfig.setDigest(zkConfig.getDigest()); System.out.println("初始化job注册中心配置成功"+zkConfig.getNamespace()); return new ZookeeperRegistryCenter(zkConfig); } @Bean public ElasticJobConfParser elasticJobConfParser(JobZookeeperProperties jobZookeeperProperties,ZookeeperRegistryCenter zookeeperRegistryCenter) { return new ElasticJobConfParser(jobZookeeperProperties,zookeeperRegistryCenter); } } package com.cc.rabbit.task.parser; import com.cc.rabbit.task.autoconfigure.JobZookeeperProperties; import com.dangdang.ddframe.job.reg.zookeeper.ZookeeperRegistryCenter; public class ElasticJobConfParser { private JobZookeeperProperties jobZookeeperProperties; private ZookeeperRegistryCenter zookeeperRegistryCenter; public ElasticJobConfParser(JobZookeeperProperties jobZookeeperProperties, ZookeeperRegistryCenter zookeeperRegistryCenter) { this.jobZookeeperProperties = jobZookeeperProperties; this.zookeeperRegistryCenter = zookeeperRegistryCenter; } }

logic:

1. 应用时添加@EnableElasticJob注解;

2.@EnableElasticJob加载JobParserAutoConfigure配置;

3.JobParserAutoConfigure先判断@ConditionalOnProperty条件是否满足,如果满足会将application.properties中配置的参数全部读入JobZookeeperProperties对象;

4.初始化zk(ZookeeperRegistryCenter);

5.初始化es-job(ElasticJobConfParser),ElasticJobConfParser专注解析@ElasticJobConfig注解;

step8. 通过ElasticJobTypeEunm(eunm枚举)来定义es-job的三种作业类型:

package com.cc.rabbit.task.enums; public enum ElasticJobTypeEunm { SIMPLE("SimpleJob","简单类型job"), DATAFLOW("DataflowJob","流式类型job"), SCRIPT("ScriptJob","脚本类型job"); private String type; private String desc; private ElasticJobTypeEunm(String type,String desc) { this.type = type; this.desc = desc; } public String getType() { return type; } public void setType(String type) { this.type = type; } public String getDesc() { return desc; } public void setDesc(String desc) { this.desc = desc; } }

step9. ElasticJobConfParser解析es-job的时机,ElasticJobConfParser与spring直接存在某种依赖关系,那么对于ElasticJobConfParser解析es-job的恰当时机就要在spring提供的一些机制中根据业务场景进行确定,此处举例为分布式定时任务的基础封装,在诸多场景中最为合理的是当应用服务都启动以后,即所有的springBean加载完成后,做es-job的解析,定时任务场景本身就是对于应用服务进行定时作业的一种机制,所有必须保证规划的应用已经存在,才能生效;初始化过程为,先初始化es-job相关的JobCoreConfiguration、SimpleJobConfiguration及LiteJobConfiguration,然后在构建SpringJobScheduler;对比前期代码实现的集成方式,逻辑为相反;

package com.cc.rabbit.task.parser; import java.util.Iterator; import java.util.List; import java.util.Map; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.beans.factory.support.ManagedList; import org.springframework.boot.context.event.ApplicationReadyEvent; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationListener; import org.springframework.util.StringUtils; import com.cc.rabbit.task.annotation.ElasticJobConfig; import com.cc.rabbit.task.autoconfigure.JobZookeeperProperties; import com.cc.rabbit.task.enums.ElasticJobTypeEunm; import com.dangdang.ddframe.job.config.JobCoreConfiguration; import com.dangdang.ddframe.job.config.JobTypeConfiguration; import com.dangdang.ddframe.job.config.dataflow.DataflowJobConfiguration; import com.dangdang.ddframe.job.config.script.ScriptJobConfiguration; import com.dangdang.ddframe.job.config.simple.SimpleJobConfiguration; import com.dangdang.ddframe.job.event.rdb.JobEventRdbConfiguration; import com.dangdang.ddframe.job.executor.handler.JobProperties; 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; public class ElasticJobConfParser implements ApplicationListener<ApplicationReadyEvent>{ private JobZookeeperProperties jobZookeeperProperties; private ZookeeperRegistryCenter zookeeperRegistryCenter; public ElasticJobConfParser(JobZookeeperProperties jobZookeeperProperties, ZookeeperRegistryCenter zookeeperRegistryCenter) { this.jobZookeeperProperties = jobZookeeperProperties; this.zookeeperRegistryCenter = zookeeperRegistryCenter; } @Override public void onApplicationEvent(ApplicationReadyEvent event) { try { //获取应用上下文 ApplicationContext applicationContext = event.getApplicationContext(); //获取所有添加@ElasticJobConfig注解的bean Map<String, Object> beanMap = applicationContext.getBeansWithAnnotation(ElasticJobConfig.class); //循环所有Bean,独立配置,初始化相关内容 for(Iterator<?> it = beanMap.values().iterator();it.hasNext();) { Object confBean = it.next(); Class<?> clazz = confBean.getClass(); //如果是一个子类,匿名或带有“$”符号,将真正的名字取出复制给clazz if(clazz.getName().indexOf("$") > 0) { String className = clazz.getName(); //从0截取到$前为真正的类名 clazz = Class.forName(className.substring(0,className.indexOf("$"))); } /* 获取接口类型,用于判断任务类型(简单类型、流式、脚本) * 此处简写,取第一个interface; * 正常生产中类可能实现多个interface,要遍历判断; */ String jobTypeName = clazz.getInterfaces()[0].getSimpleName(); //获取ElasticJobConfig的配置项 ElasticJobConfig conf = clazz.getAnnotation(ElasticJobConfig.class); String jobClass = clazz.getName(); //防止重复:使用Namespace加jobname组合 //String jobName = conf.jobName(); String jobName = this.jobZookeeperProperties.getNamespace() +"."+ conf.jobName(); String cron = conf.cron(); String shardingItemParameters = conf.shardingItemParameters(); String description = conf.description(); String jobParameter = conf.jobParameter(); String jobExceptionHandler = conf.jobExceptionHandler(); String executorServiceHandler = conf.executorServiceHandler(); String jobShardingStrategyClass = conf.jobShardingStrategyClass(); String eventTraceRdbDataSource = conf.eventTraceRdbDataSource(); String scriptCommandLine = conf.scriptCommandLine(); boolean failover = conf.failover(); boolean misfire = conf.misfire(); boolean overwrite = conf.overwrite(); boolean disabled = conf.disabled(); boolean monitorExecution = conf.monitorExecution(); boolean streamingProcess = conf.streamingProcess(); int shardingTotalCount = conf.shardingTotalCount(); int monitorPort = conf.monitorPort(); int maxTimeDiffSeconds = conf.maxTimeDiffSeconds(); int reconcileIntervalMinutes = conf.reconcileIntervalMinutes(); // 1 先将当当网的esjob相关configuration实例化(然后在与spring做集成) JobCoreConfiguration coreConfig = JobCoreConfiguration .newBuilder(jobName, cron, shardingTotalCount) .shardingItemParameters(shardingItemParameters) .description(description) .failover(failover) .jobParameter(jobParameter) .misfire(misfire) .jobProperties(JobProperties.JobPropertiesEnum.JOB_EXCEPTION_HANDLER.getKey(), jobExceptionHandler) .jobProperties(JobProperties.JobPropertiesEnum.EXECUTOR_SERVICE_HANDLER.getKey(), executorServiceHandler) .build(); /* 2 确定创建任务的类型 * 通过判断继承接口的名字与ElasticJobTypeEunm枚举中定义的属性值是否一致来判断任务类型; */ JobTypeConfiguration typeConfig = null; if(ElasticJobTypeEunm.SIMPLE.getType().equals(jobTypeName)) { typeConfig = new SimpleJobConfiguration(coreConfig, jobClass); } if(ElasticJobTypeEunm.DATAFLOW.getType().equals(jobTypeName)) { typeConfig = new DataflowJobConfiguration(coreConfig, jobClass, streamingProcess); } if(ElasticJobTypeEunm.SCRIPT.getType().equals(jobTypeName)) { typeConfig = new ScriptJobConfiguration(coreConfig, scriptCommandLine); } // 3 初始化LiteJobConfiguration LiteJobConfiguration jobConfig = LiteJobConfiguration .newBuilder(typeConfig) .overwrite(overwrite) .disabled(disabled) .monitorPort(monitorPort) .monitorExecution(monitorExecution) .maxTimeDiffSeconds(maxTimeDiffSeconds) .jobShardingStrategyClass(jobShardingStrategyClass) .reconcileIntervalMinutes(reconcileIntervalMinutes) .build(); // 4 创建一个spring的beanDefiniton BeanDefinitionBuilder factory = BeanDefinitionBuilder.rootBeanDefinition(SpringJobScheduler.class); factory.setInitMethodName("init"); factory.setScope("prototype"); //多例(非单例) // // -1.添加bean构造参数,相当于添加自己的真实的任务实现类 if (!ElasticJobTypeEunm.SCRIPT.getType().equals(jobTypeName)) { factory.addConstructorArgValue(confBean); } // -2.添加注册中心 factory.addConstructorArgValue(this.zookeeperRegistryCenter); // -3.添加LiteJobConfiguration factory.addConstructorArgValue(jobConfig); // -4.如果有eventTraceRdbDataSource 则也进行添加 if (StringUtils.hasText(eventTraceRdbDataSource)) { BeanDefinitionBuilder rdbFactory = BeanDefinitionBuilder.rootBeanDefinition(JobEventRdbConfiguration.class); rdbFactory.addConstructorArgReference(eventTraceRdbDataSource); factory.addConstructorArgValue(rdbFactory.getBeanDefinition()); } // 5.添加监听 List<?> elasticJobListeners = getTargetElasticJobListeners(conf); factory.addConstructorArgValue(elasticJobListeners); // 6.把factory也就是 SpringJobScheduler注入到Spring容器中 DefaultListableBeanFactory defaultListableBeanFactory = (DefaultListableBeanFactory) applicationContext.getAutowireCapableBeanFactory(); String registerBeanName = conf.jobName() + "SpringJobScheduler"; defaultListableBeanFactory.registerBeanDefinition(registerBeanName, factory.getBeanDefinition()); SpringJobScheduler scheduler = (SpringJobScheduler)applicationContext.getBean(registerBeanName); scheduler.init(); System.out.println("启动elastic-job作业: " + jobName); } System.out.println("共计启动elastic-job作业数量为:"+beanMap.values().size()+"个"); } catch (Exception e) { System.out.println("elasticjob 启动异常, 系统强制退出"); System.exit(1); } } private List<BeanDefinition> getTargetElasticJobListeners(ElasticJobConfig conf) { List<BeanDefinition> result = new ManagedList<BeanDefinition>(2); String listeners = conf.listener(); if (StringUtils.hasText(listeners)) { BeanDefinitionBuilder factory = BeanDefinitionBuilder.rootBeanDefinition(listeners); factory.setScope("prototype"); result.add(factory.getBeanDefinition()); } String distributedListeners = conf.distributedListener(); long startedTimeoutMilliseconds = conf.startedTimeoutMilliseconds(); long completedTimeoutMilliseconds = conf.completedTimeoutMilliseconds(); if (StringUtils.hasText(distributedListeners)) { BeanDefinitionBuilder factory = BeanDefinitionBuilder.rootBeanDefinition(distributedListeners); factory.setScope("prototype"); factory.addConstructorArgValue(Long.valueOf(startedTimeoutMilliseconds)); factory.addConstructorArgValue(Long.valueOf(completedTimeoutMilliseconds)); result.add(factory.getBeanDefinition()); } return result; } }

step10. 测试es-job组件封装:

1.创建测试项目rabbit-es-job并将rabbit-task依赖引入:

2.配置application.properties,配置必要的两个参数属性namespace和serverLists

server.port=8881 elastic.job.zk.namespace=elastic-job elastic.job.zk.serverLists=192.168.85.140:2182,192.168.85.142:2182,192.168.85.141:2182 #mysql数据源 spring.datasource.url=jdbc:mysql://localhost:3306/elasticjob?useUnicode=true&characterEncoding=utf-8&verifyServerCertificate=false&useSSL=false&requireSSL=false spring.datasource.driver-class-name=com.mysql.jdbc.Driver spring.datasource.username=root spring.datasource.password=root

3.将自定义注解@EnableElasticJob添加到Application

package com.cc.es; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import com.cc.rabbit.task.annotation.EnableElasticJob; @EnableElasticJob @SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }

4.创建定时任务TestJob与DemoJob做为测试:必须添加@Component注解将测试类注入spring容器;通过@ElasticJobConfig自定义注解配置定时任务参数;<必须开启虚拟机的zookeeper作为测试>

package com.cc.es.task.test; import org.springframework.stereotype.Component; import com.cc.rabbit.task.annotation.ElasticJobConfig; import com.dangdang.ddframe.job.api.ShardingContext; import com.dangdang.ddframe.job.api.simple.SimpleJob; @Component @ElasticJobConfig( jobName = "com.cc.es.task.test.TestJob", cron = "0/5 * * * * ?", description = "测试定时任务", overwrite = true, shardingTotalCount = 5 ) public class TestJob implements SimpleJob{ @Override public void execute(ShardingContext shardingContext) { System.out.println("-----执行Test job!"); } } package com.cc.es.task.test; import org.springframework.stereotype.Component; import com.cc.rabbit.task.annotation.ElasticJobConfig; import com.dangdang.ddframe.job.api.ShardingContext; import com.dangdang.ddframe.job.api.simple.SimpleJob; @Component @ElasticJobConfig( jobName = "com.cc.es.task.test.DemoJob", cron = "0/10 * * * * ?", description = "样例测试定时任务", overwrite = true, shardingTotalCount = 5 ) public class DemoJob implements SimpleJob{ @Override public void execute(ShardingContext shardingContext) { System.out.println("-----执行Demo Job!"); } }

5.运行Application测试输出:

ElasticJob基础组件封装完成,测试通过。

最新回复(0)