使用背景
由于项目中有很多的定时任务,需要在指定时间或者是某段时间范围内自动触发,因此需要有一款定时任务的框架,查看公司定时任务工程后,发现是基于Elastic-job来实现的。只不过进行了一些定制化改造。
简介
elastic-job 是由当当网基于quartz 二次开发之后的分布式调度解决方案 , 由两个相对独立的子项目Elastic-Job-Lite和Elastic-Job-Cloud组成 。一般项目使用lite版本即可满足要求。
Elastic-Job采用去中心化设计,主要分为注册中心、数据分片、分布式协调、定时任务处理和定制化流程型任务等模块。
Elastic-Job主要的设计理念是无中心化的分布式定时调度框架,思路来源于Quartz的基于数据库的高可用方案。但数据库没有分布式协调功能,所以在高可用方案的基础上增加了弹性扩容和数据分片的思路,以便于更大限度的利用分布式服务器的资源。
作业开发
Elastic-Job提供Simple、Dataflow和Script 3种作业类型。方法参数shardingContext包含作业配置、片和运行时信息。可通过getShardingTotalCount(), getShardingItem()等方法分别获取分片总数,运行在本作业服务器的分片序列号等。
Simple类型的作业:该类型意为简单实现,只需实现SimpleJob接口,重写它的execute方法即可。
Dataflow类型作业:用于处理数据流,实现DataflowJob接口,并重写两个方法——用于抓取(fetchData方法)和处理(processData方法)数据。
Script类型作业:意为脚本类型作业,支持shell、python、perl等类型脚本。只需通过控制台或代码配置scriptCommandLine即可,无需编码。
由于Elastic-Job是基于Quratz来封装的,我们先看一下Quartz是如何来提交一个作业任务的:
Quratz Demo
(1)导入依赖的jar包:
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.3.0</version>
</dependency>
(2)新建一个能够打印任意内容的Job:
public class QuartzJob implements Job{
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
String printTime = new SimpleDateFormat("yy-MM-dd HH-mm-ss").format(new Date());
System.out.println("QuartzJob start at:" + printTime + ", prints: Hello Job-" + new Random().nextInt(100));
}
}
(3)创建Schedule,执行任务:
public class MyScheduler {
public static void main(String[] args) throws SchedulerException, InterruptedException {
// 1、创建调度器Scheduler
SchedulerFactory schedulerFactory = new StdSchedulerFactory();
Scheduler scheduler = schedulerFactory.getScheduler();
// 2、创建JobDetail实例,并与QuartzJob 类绑定(Job执行内容)
JobDetail jobDetail = JobBuilder.newJob(QuartzJob .class)
.withIdentity("job1", "group1").build();
// 3、构建Trigger实例,每隔1s执行一次
Trigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger1", "triggerGroup1")
.startNow()//立即生效
.withSchedule(
//CronScheduleBuilder.cronSchedule("* 30 10 ? * 1/5 2018") cron表达式类型
SimpleScheduleBuilder.simpleSchedule()
.withIntervalInSeconds(1)//每隔1s执行一次
.repeatForever()).build();//一直执行
//4、执行
scheduler.scheduleJob(jobDetail, trigger);
System.out.println("scheduler start !");
scheduler.start();
//睡眠
TimeUnit.MINUTES.sleep(1);
scheduler.shutdown();
System.out.println("scheduler shutdown ! ");
}
}
通过控制台可以看到,每秒都会打印出内容:
Elastic-Job-Lite实现:
项目对原有Elastic-Job-Lite进行了一些改造,新增ElasticJobConfig自定义注解,用来配置分片信息,cron表达式等信息,新增ElasticJobAutoConfig,用来自定义初始化。
1.入口 (要执行的任务是JavaSimpleJob.java)
各种配置:项目中首先是注册中心配置(zk),ElasticJobAutoConfig(作业执行的配置),ElasticJobConfig(作业参数配置)
目前作业任务 job 是通过 LiteJobConfiguration 来定义的,里面会定义是哪一种类型的job(JobTypeConfiguration)。
现在支持3种类型的job:SimpleJobConfiguration、DataflowJobConfiguration、ScriptJobConfiguration。任务会在autoconfig中完成init并启动
2.JobScheduler
最后一行的SpringJobScheduler继承自JobScheduler,JobScheduler 实例化时,在构造函数中会构造JobFacade(用来操作分片上下文的)。在JobScheduler的init()方法中,创建了JobDetail。
在init()方法最后,会调用JobSchedulerController的scheduleJob方法,完成启动:
通过上面的elastic-job的配置过程,可看出是符合Quratz的,到了cron表达式设定的执行时间,Quartz会去执行LiteJob#execute()。