代码git地址:https://gitee.com/hankin_chj/schedule-job-platform.git
一、任务调度的基本用法
1、Quartz Scheduler开源框架
Quartz是开源任务调度框架中的翘首,是java业务界事实上的任务调度标准。 Quartz提供了强大任务调度机制,而且使用简单。Quartz允许开发人员灵活地定义触发器的调度时间表,并可以对触发器和任务进行关联映射。此外Quartz提供了调度运行环境的持久化机制,可以保存并恢复调度现场,即使系统因故障关闭,任务调度现场数据并不会丢失。此外Quartz还提供了组件式的侦听器、各种插件、线程池等功能。
2、Quartz的核心元素
- Quartz主要涉及以下元素概念:
- scheduler:任务调度器;
- trigger:触发器,用于定义任务调度时间规则;
- job:任务,即被调度的任务;
- misfire:错过的,指本来应该被执行但实际没有被执行的任务调度其中trigger和job是任务调度的元数据,scheduler是实际执行调度的控制器。
- trigger是用于定义调度时间的元素,即按照什么时间规则去执行任务。Quartz中主要提供了四种类型的trigger:SimpleTrigger,CronTirgger,DateIntervalTrigger和NthIncludedDayTrigger。这四种trigger可以满足企业应用中的绝大部分需求。我们将在企业应用一节中进一步讨论四种trigger的功能。
- job用于表示被调度的任务。主要有两种类型的 job:无状态的(stateless)和有状态的(stateful)。对于同一个trigger来说,有状态的job不能被并行执行,只有上一次触发的任务被执行完之后,才能触发下一次执行。Job主要有两种属性:volatility和durability,其中volatility表示任务是否被持久化到数据库存储,而durability表示在没有trigger关联的时候任务是否被保留。两者都是在值为true的时候任务被持久化或保留。
一个job可以被多个trigger关联,但是一个trigger只能关联一个job。 scheduler由scheduler工厂创建:DirectSchedulerFactory或者StdSchedulerFactory。 一般使用StdSchedulerFactory工厂较多。Scheduler主要有三种:RemoteMBeanScheduler,RemoteScheduler和StdScheduler,最常用的为StdScheduler。
核心元素间关系如下图:
3、Quartz的线程
在Quartz中,有两类线程,Scheduler调度线程和任务执行线程,其中任务执行线程通常使用一个线程池维护一组线程。
Scheduler调度线程主要有两个:执行常规调度的线程,和执行misfired trigger的线程。常规调度线程轮询存储的所有trigger,如果有需要触发的trigger,即到达了下一次触发的时间,则从任务执行线程池获取一个空闲线程,执行与该trigger关联的任务。Misfire线程是扫描所有的trigger,查看是否有misfired trigger,如果有的话根据misfire的策略分别处理。
4、数据存储
Quartz中的trigger和job需要存储下来才能被使用。Quartz中有两种存储方式:RAMJobStore、JobStoreSupport,其中RAMJobStore是将 trigger和job存储在内存中, 而JobStoreSupport是基 jdbc将trigger 和job存储到数据库中。RAMJobStore的存取速度非常快,但是由于其在系统被停止后所有的数据都会丢失, 所以在通常应用中,都是使用JobStoreSupport。
在Quartz中,JobStoreSupport使用一个驱动代理来操作trigger和job的数据存储:StdJDBCDelegate。StdJDBCDelegate实现了大部分基于标准JDBC的功能接口,但是对于各种数据库来说,需要根据其具体实现的特点做某些特殊处理,因此各种数据库需要扩展StdJDBCDelegate以实现这些特殊处理。Quartz已经自带了一些数据库的扩展实现,可以直接使用。
5、Quartz的用法
5.1、配置目标任务
使用Spring Quartz实现Job任务有两种方式,一种是实现org.quartz.Job接口,这个不推荐。另一种不需要继承,只需要在配置文件中定义MethodInvokingJobDetailFactoryBean,并指定它的targetObject属性为Job任务类,targetMethod属性为任务方法就可以了。targetObject 属性指定目标对象。
@Configuration
public class QuartzConfig {
/**
* 耦合业务
* TODO 将调度环境信息传递给业务方法,如:调度时间,批次等
*/
@Bean(name = "businessJobDetail")
public JobDetailFactoryBean businessJobDetail() {
JobDetailFactoryBean jobDetailFactoryBean = new JobDetailFactoryBean();
//业务bean是多例的还是单例的? 多例
jobDetailFactoryBean.setJobClass(BusinessJob.class);
//TODO 将参数封装传递给job
JobDataMap jobDataMap =new JobDataMap();
jobDataMap.put("time",System.currentTimeMillis());
jobDetailFactoryBean.setJobDataAsMap(jobDataMap);
return jobDetailFactoryBean;
}
//TODO 普通业务类
@Bean(name = "serviceBeanDetail")
public MethodInvokingJobDetailFactoryBean serviceBeanDetail(XXXService serviceBean) {//业务bean,单例的
MethodInvokingJobDetailFactoryBean jobDetail = new MethodInvokingJobDetailFactoryBean();
//TODO 是否并发执行
jobDetail.setConcurrent(false);
// TODO 需要执行的实体bean
jobDetail.setTargetObject(serviceBean);
// TODO 需要执行的方法
jobDetail.setTargetMethod("business");
return jobDetail;
}
5.2、配置触发器
//TODO 简单触发器
@Bean(name = "simpleTrigger")
public SimpleTriggerFactoryBean simpleTrigger(JobDetail businessJobDetail) {
SimpleTriggerFactoryBean trigger = new SimpleTriggerFactoryBean();
trigger.setJobDetail(businessJobDetail);
// TODO 设置任务启动延迟
trigger.setStartDelay(0);
//TODO 每5秒执行一次
trigger.setRepeatInterval(3000);
return trigger;
}
//TODO cron触发器
@Bean(name = "cronTrigger")
public CronTriggerFactoryBean cronTrigger(JobDetail serviceBeanDetail) {
CronTriggerFactoryBean triggerFactoryBean = new CronTriggerFactoryBean();
triggerFactoryBean.setJobDetail(serviceBeanDetail);
triggerFactoryBean.setCronExpression("0/6 * * * * ?");
return triggerFactoryBean;
}
5.3、配置调度工厂
//TODO 调度工厂,将所有的触发器引入
@Bean(name = "scheduler")
public SchedulerFactoryBean schedulerFactory(Trigger simpleTrigger, Trigger cronTrigger) {
SchedulerFactoryBean bean = new SchedulerFactoryBean();
//TODO 延时启动,应用启动1秒后
bean.setStartupDelay(1);
//TODO 注册触发器
bean.setTriggers(simpleTrigger,cronTrigger);
return bean;
}
5.4、具体某个定时任务调度的业务实现
public class BusinessJob implements Job{
int i = 0;
public void execute(JobExecutionContext context) throws JobExecutionException {
JobDataMap dataMap = context.getJobDetail().getJobDataMap();
String name = dataMap.get("time").toString();
business(name);
}
//重型任务,1000W数据统计,把任务敲碎 -- E-job
private void business(String time){
i++;
System.out.println("BusinessJob start --- time:"+time+", thread:" + Thread.currentThread().getName() );
}
}
到此,整个配置就完成了。
6、spring task调度器用法
Spring从3.0开始增加了自己的任务调度器,它是通过扩展java.util.concurrent包下面的类来实现的,它也使用Cron表达式。使用spring task非常简单,只需要给定时任务类添加@Component 注解,给任务方法添加@Scheduled(cron = "0/5 * * * * ?")注解,并让 Spring 扫描到该类即可。
如果定时任务很多,可以配置executor线程池,这里executor的含义和java.util.concurrent.Executor是一样的,pool-size的大小官方推荐为5~10。scheduler pool-size是ScheduledExecutorService线程池。
6.1、定时任务线程池配置:
/**
* 没有此配置,则schedule为单线程串行执行
*/
@Configuration
@EnableScheduling
public class ScheduleConfig implements SchedulingConfigurer {
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
taskRegistrar.setScheduler(taskExecutor());
}
//配置线程池---触发器和任务共用的
@Bean(destroyMethod="shutdown")
public Executor taskExecutor() {
return Executors.newScheduledThreadPool(10);
}
}
6.2、定时任务实现代码:
具体定时任务配置通过@EnableScheduling与@Scheduled(cron = "0/5 * * * * ?")来实现
@Component
@EnableScheduling
public class TaskConfig {
private static final SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");
@Scheduled(fixedDelayString = "5000") //单机
public void getTask1() {
//TODO 竞争锁逻辑代码 .....
System.out.println("任务1,当前时间:" + dateFormat.format(new Date())+",线程号:"
+Thread.currentThread().getName());
throw new RuntimeException("xxxxx");
}
@Scheduled(cron = "0/5 * * * * ?")
public void getTask2() {
System.out.println("任务2,当前时间:" + dateFormat.format(new Date())+",线程号:"
+Thread.currentThread().getName());
}
}
7、cron表达式:
- *:表示匹配该域的任意值。
- ?:只能用在DayofMonth和DayofWeek两个域,表示匹配域的任意值。
- -:表示范围
- /:表示起始时间开始触发,然后每隔固定时间触发一次
- ,:表示列出枚举值值。
- L:表示最后,只能出现在DayofWeek和DayofMonth域
- W: 表示有效工作日(周一到周五),只能出现在DayofMonth域
- LW:这两个字符可以连用,表示在某个月最后一个工作日,即最后一个星期五。
- #:用于确定每个月第几个星期几,只能出现在DayofMonth域。例如在4#2,表示某月的第二个星期三。
二、分布式任务调度
在系统需要运行大量耗时定时任务的场景下,单使用类似Quartz或者spring task等定时任务框架无法满足对并发处理性能、监控管理及运维拓展的要求。此时,定时任务主要面临以下几个新问题: l
- 多节点重复执行某一任务;
- 大量的任务管理困难;
- 某些大型任务耗时超长,需要切分给多台机器并行执行;
简单地说,如果仅仅面向解决第一个问题,我们可以借助分布式锁,来规避节点的执行难题(有兴趣的可参考分布式锁的使用)。
下面我们主要介绍elastic-job和xxl-job这两个框架:
共同点: E-Job和X-job都有广泛的用户基础和完整的技术文档,都能满足定时任务的基本功能需求。
不同点:
X-Job侧重的业务实现的简单和管理的方便,学习成本简单,失败策略和路由策略丰富。推荐使用在“用户基数相对少,服务器数量在一定范围内,任务数量多”的情景下使用。
E-Job关注的是数据,增加了弹性扩容和数据分片的思路,以便于更大限度的利用分布式服务器的资源。但是学习成本相对高些, 推荐在“数据量庞大,且部署服务器数量较多”时使用。
1、E-Job分布式调度
Elastic-Job是一个分布式调度解决方案,由两个相互独立的子项目Elastic-Job-Lite和Elastic-Job-Cloud组成。Elastic-Job-Lite定位为轻量级无中心化解决方案,使用jar包的形式提供分布式任务的协调服务。基于quartz定时任务框架为基础的,因此具备quartz的大部分功能使用zookeeper做协调,调度中心,更加轻量级。
支持任务的分片、支持弹性扩容,可以水平扩展,当任务再次运行时,会检查当前的服务器数量,重新分片,分片结束之后才会继续执行任务失效转移,容错处理,当一台调度服务器宕机或者跟zookeeper断开连接之后,会立即停止作业,然后再去寻找其他空闲的调度服务器,来运行剩余的任务提供运维界面,可以管理作业和注册中心。
我们主要介绍 Elastic-Job-Lite的去中心化解决方案。
1.2、使用场景
当今互联网项目大多为微服务,单模块可能在两个实例以上的数量,定时器就会出现多实例同时执行的情况。同时,我们的某些 任务可能还存在过大,需要切片来加速执行等需求,归结如下: ·
- 分布式调度协调;
- 弹性扩容缩容;
- 失效转移;
- 错过执行作业重触发;
- 作业分片一致性,保证同一分片在分布式环境中仅一个执行实例;
- 自诊断并修复分布式不稳定造成的问题;
- 支持并行调度;
- 支持作业生命周期操作;
- 丰富的作业类型;
- Spring 整合以及命名空间提供;
运维平台Elastic-Job-Lite以其简单易用,无中心化方式,非常适合用来简单整合普通业务。
1.3、添加依赖
<!-- 注意elastic在maven默认的中央仓库里面没有,需要单独配置拉去 -->
<dependency>
<groupId>com.github.yinjihuan</groupId>
<artifactId>elastic-job-spring-boot-starter</artifactId>
<version>1.0.2</version>
</dependency>
<repositories>
<repository>
<id>jitpack.io</id>
<url>https://jitpack.io</url>
</repository>
</repositories>
1.4、配置
ps: 需要zookeeper支持,请提前搭建好,配置application.properties加入以下配置:
# zk注册中心
elastic.job.zk.serverLists=127.0.0.1:2181
elastic.job.zk.namespace=hankin_elastic7
spring.main.allow-bean-definition-overriding=true
server.port=8283
配置很简单,只需要加入zk注册中心地址和job名称空间即可。
1.5、定时器实现方法编写
例如实现一个简单的定时任务:
@ElasticJobConf(name = "MySimpleJob",cron = "0/5 * * * * ?"
,shardingItemParameters = "0=beijing|shenzhen|tianjin,1=shanghai",shardingTotalCount = 2
,listener = "com.chj.handle.MessageElasticJobListener"
,jobExceptionHandler = "com.chj.handle.CustomJobExceptionHandler"
)
public class MySimpleJob implements SimpleJob {
@Autowired
private MyBusiness myBusiness;
public void execute(ShardingContext context) {
System.out.println("MySimpleJob,当前分片:"+context.getShardingParameter());
//TODO 当前起始 context.getShardingParameter(),回返切片信息beijing
String sql = myBusiness.getSql(context.getShardingParameter());
myBusiness.process(sql);
}
}
作业监听器需要实现ElasticJobListener 接口:
public class MessageElasticJobListener implements ElasticJobListener {
@Override
public void beforeJobExecuted(ShardingContexts shardingContexts) {
String date = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
String msg = date + " 【任务开始执行-" + shardingContexts.getJobName() + "】";
System.out.println("给管理发邮件:"+msg);
}
@Override
public void afterJobExecuted(ShardingContexts shardingContexts) {
String date = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
String msg = date + " 【任务执行结束-" + shardingContexts.getJobName() + "】" ;
System.out.println("给管理发邮件:"+msg);
}
}
自定义异常处理需要实现JobExceptionHandler接口
public class CustomJobExceptionHandler implements JobExceptionHandler {
private Logger logger = LoggerFactory.getLogger(CustomJobExceptionHandler.class);
@Override
public void handleException(String jobName, Throwable cause) {
logger.error(String.format("Job '%s' exception occur in job processing", jobName), cause);
System.out.println("给管理发邮件:【"+jobName+"】任务异常。" + cause.getMessage());
}
}
具体执行的业务方法:
@Service
public class MyBusiness {
private String sql_tpl = "select * from xxx where param = %s";
public String getSql(String param){
return String.format(sql_tpl,param);
}
//index指示,现在跑的是第几片;total指示,总共有几片
public void process(String sql) {
//分片任务
System.out.println("当前执行sql:"+sql);
}
}
1.6、定时任务的几种实现方式
Elastic-job总共提供了三种类型的定时任务:Simple类型定时任务、Dataflow类型定时任务和Script类型定时任务。其中Script类型作业意为脚本类型作业,支持shell,python和perl等所有类型脚本,应用得不太多。
SimpleJob需要实现SimpleJob接口,是未经过任何封装的定时任务简单实现,与quartz原生接口相似。Dataflow类型的定时任务主要用于处理数据流,需实现DataflowJob接口。该接口可以提供2个方法可供覆盖,分别用于抓取(fetchData)和处理(processData)数据。
推荐使用ElasticJobConf注解方:
@ElasticJobConf(name = "EnjoySimpleJob",cron = "0/5 * * * * ?"
,shardingItemParameters = "0=beijing,1=shanghai",
shardingTotalCount = 2 ,
listener = "com.enjoy.handle.MessageElasticJobListener" ,
jobExceptionHandler = "com.chj.handle.CustomJobExceptionHandler
)
ElasticJobConf 的常用的参数释义如下:
cron:cron表达式,用于配置作业触发时间;
sharding-total-count 作业分片总数;
sharding-item-parameters:分片序列号和参数用等号分隔,多个键值对用逗号分隔 分片序列号从 0 开始,不可大于或等于作业分片总数 如:0=a,1=b,2=c。
job-parameter:作业自定义参数,可以配置多个相同的作业,但是用不同的参数作为不同的调度实例
Misfire:是否开启错过任务重新执行。
Listener:任务开始和结束时,自定义的处理功能。
jobExceptionHandler:任务异常时,自定义的处理。
1.7、任务启动
对于springboot来说,使用EnableElasticJob标注ElasticJob即可。
@SpringBootApplication
@EnableElasticJob
public class ElasticJobApp {
public static void main(String[] args) {
SpringApplication.run(ElasticJobApp.class,args);
}
}
2、X-Job分布式调度
XXL-JOB是一个轻量级分布式任务调度平台,其核心设计目标是开发迅速、学习简单、轻量级、易扩展。现已开放源代码,并接入多家公司线上产品线,开箱即用。与 E-Job走无中心化方式不同,XXL-JOB是中心集权方式。
2.1、使用场景
基于spring,quartz,netty开源定时任务框架,解决的问题是不用每一个job-client都需要集成quartz,管 理 cron 配置,尤其 job 很多的时候当容器启动会执行一堆 job,影响启动速度。 原理简单而言就是由 job 配置中心管理通过 quartz 控制客户端 job 触发时机,然后通过 netty rpc 调用执行客户端的具体 实现。这样中心化的方式可以极大改善 job 的管理成本,还可以配置集群。
下面是其全景图:
xxl-job的官方文档非常详细,可以到这里查看:https://www.xuxueli.com/xxl-job/#/
本文,我们主要讲解一个其基本的搭建与使用流
2.2、部署调度中心
作为中心化的调度平台,xxl的调度中心当然是核心中的核心。其作用:统一管理任务调度平台上调度任务,负责触发调度执行,并且提供任务管理平台。
你可以 github 下载:https://github.com/xuxueli/xxl-job
下载好代码包后,第一步执行 doc 中的 db 脚本,创建好数据库表。
然后更改调度中心配置文件地址:/xxl-job/xxl-job-admin/src/main/resources/xxl-job-admin.properties
启动:直接启动 XxlJobAdminApplication 即可
### web
server.port=8080
server.context-path=/xxl-job-admin
### resources
spring.mvc.static-path-pattern=/static/**
spring.resources.static-locations=classpath:/static/
### freemarker
spring.freemarker.templateLoaderPath=classpath:/templates/
spring.freemarker.suffix=.ftl
spring.freemarker.charset=UTF-8
spring.freemarker.request-context-attribute=request
spring.freemarker.settings.number_format=0.##########
### mybatis
mybatis.mapper-locations=classpath:/mybatis-mapper/*Mapper.xml
### xxl-job, datasource
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/xxljob?Unicode=true&characterEncoding=UTF-8&useSSL=false
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.type=org.apache.tomcat.jdbc.pool.DataSource
spring.datasource.tomcat.max-wait=10000
spring.datasource.tomcat.max-active=30
spring.datasource.tomcat.test-on-borrow=true
spring.datasource.tomcat.validation-query=SELECT 1
spring.datasource.tomcat.validation-interval=30000
### xxl-job email
spring.mail.host=smtp.qq.com
spring.mail.port=25
spring.mail.username=xxx@qq.com
spring.mail.password=xxx
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.starttls.enable=true
spring.mail.properties.mail.smtp.starttls.required=true
### xxl-job login
xxl.job.login.username=admin
xxl.job.login.password=123456
### xxl-job, access token
xxl.job.accessToken=
### xxl-job, i18n (default empty as chinese, "en" as english)
xxl.job.i18n=
2.3、调度中心集群
在生产环境中,需要提升调度系统容灾和可用性,调度中心支持集群部署,只需要多台部署连接同一套数据库即可。
- DB 配置保持一致;
- 登陆账号配置保持一致;
- 集群机器时钟保持一致(单机集群忽视);
建议:推荐通过nginx为调度中心集群做负载均衡,分配域名。
调度中心访问、执行器回调配置、调用 API 服务等操作均通过该域名进行。
2.4、部署执行项目
执行器就是我们的业务系统,负责接收“调度中心”的调度并执行业务任务;下面简介集成步骤:
步骤1:引入 xxl-job-core的依赖
<dependency>
<groupId>com.xuxueli</groupId>
<artifactId>xxl-job-core</artifactId>
<version>2.0.2</version>
</dependency>
步骤2:执行器配置
在application.properties下的配置信息信息如下:
### 调度器的地址----- 发消息
xxl.job.admin.addresses=http://localhost:8080/xxl-job-admin
### 当前执行器的标识名称,同一个名字的执行器构成集群
xxl.job.executor.appname=xxl-job
# 执行器与调度器通信的ip / port
xxl.job.executor.ip=
xxl.job.executor.port=9993
### job-job, access token
xxl.job.accessToken=
### job-job log path
xxl.job.executor.logpath=/logs/xxl/job
### job-job log retention days
xxl.job.executor.logretentiondays=-1
server.port=8283
### 调度中心部署跟地址 [选填]:
如调度中心集群部署存在多个地址则用逗号分隔。执行器将会使用该地址进行"执行器心跳注 册"和"任务结果回调";为空则关闭自动注册;xxl.job.admin.addresses=http://127.0.0.1:8080/xxl-job-admin
### 执行器 AppName [选填]:
执行器心跳注册分组依据;为空则关闭自动注册 xxl.job.executor.appname= xxl-job
### 执行器 IP [选填]:
默认为空表示自动获取IP,多网卡时可手动设置指定IP,该IP不会绑定Host仅作为通讯实用;地址信息用于"执行器注册"和"调度中心请求并触发任务";xxl.job.executor.ip=
### 执行器端口号 [选填]:
小于等于0则自动获取;默认端口为9999,单机部署多个执行器时,注意要配置不同执行器端口;xxl.job.executor.port=9999
### 执行器通讯 TOKEN [选填]:非空时启用;xxl.job.accessToken=
### 执行器运行日志文件存储磁盘路径 [选填] :需要对该路径拥有读写权限;为空则使用默认路径;
xxl.job.executor.logpath=/data/applogs/xxl-job/jobhandler
### 执行器日志保存天数 [选填] :值大于 3 时生效,启用执行器 Log 文件定期清理功能,否则不生效; xxl.job.executor.logretentiondays=-1
步骤3:执行器组件配置
需要将上面的执行器各项参数,配置到 XxlJobSpringExecutor 组件中,创建如下
@Configuration
@ComponentScan(basePackages = "com.xxl.job.executor.service.jobhandler")
public class XxlConfig {
private Logger logger = LoggerFactory.getLogger(XxlConfig.class);
@Value("${xxl.job.admin.addresses}")
private String adminAddresses;
@Value("${xxl.job.executor.appname}")
private String appName;
@Value("${xxl.job.executor.ip}")
private String ip;
@Value("${xxl.job.executor.port}")
private int port;
@Value("${xxl.job.accessToken}")
private String accessToken;
@Value("${xxl.job.executor.logpath}")
private String logPath;
@Value("${xxl.job.executor.logretentiondays}")
private int logRetentionDays;
@Bean(initMethod = "start", destroyMethod = "destroy")
public XxlJobSpringExecutor xxlJobExecutor() {
logger.info(">>>>>>>>>>> job-job config init.");
XxlJobSpringExecutor xxlJobSpringExecutor = new XxlJobSpringExecutor();
xxlJobSpringExecutor.setAdminAddresses(adminAddresses);
xxlJobSpringExecutor.setAppName(appName);
xxlJobSpringExecutor.setIp(ip);
xxlJobSpringExecutor.setPort(port);
xxlJobSpringExecutor.setAccessToken(accessToken);
xxlJobSpringExecutor.setLogPath(logPath);
xxlJobSpringExecutor.setLogRetentionDays(logRetentionDays);
return xxlJobSpringExecutor;
}
}
步骤4:编写任务
任务类必须实现IJobHandler接口,它的execute方法即为执行器执行入口
/**
* 分片任务
*/
@JobHandler(value="mySharding")
@Service
public class MySharding extends IJobHandler {
@Autowired
private MyBusiness myBusiness;
@Override
public ReturnT<String> execute(String param) throws Exception {
ShardingUtil.ShardingVO shardingVO = ShardingUtil.getShardingVo();
int index = shardingVO.getIndex();
int total = shardingVO.getTotal();
myBusiness.process(index,total,param);
return SUCCESS;
}
}
@JobHandler(value="mySharding")所标的名字,demoJobHandler专为调度中指代本任务
4.5调度中心新建任务
登录调度中心,点击下图所示“新建任务”按钮,新建示例任务。然后,参考下面截图中任务的参数配置,点击保存。
3、两种分布式任务对比: