本文源码:GitHub·点这里 || GitEE·点这里

一、ElasticJob简介

1、定时任务

在前面的文章中,说过QuartJob这个定时任务,被广泛应用的定时任务标准。但Quartz核心点在于执行定时任务并不是在于关注的业务模式和场景,缺少高度自定义的功能。Quartz能够基于数据库实现任务的高可用,但是不具备分布式并行调度的功能。

-> QuartJob定时任务

2、ElasticJob说明

  • 基础简介

Elastic-Job 是一个开源的分布式调度中间件,由两个相互独立的子项目 Elastic-Job-Lite 和 Elastic-Job-Cloud 组成。Elastic-Job-Lite 为轻量级无中心化解决方案,使用 jar 包提供分布式任务的调度和治理。 Elastic-Job-Cloud 是一个 Mesos Framework,依托于Mesos额外提供资源治理、应用分发以及进程隔离等服务。

  • 功能特点
分布式调度协调
弹性扩容缩容
失效转移
错过执行作业重触发
作业分片一致性,保证同一分片在分布式环境中仅一个执行实例

补刀:人家官网这样描述的,这里赘述一下,充实一下文章。

  • 基础框架结构

该图片来自ElasticJob官网。

由图可知如下内容:

需要Zookeeper组件支持,作为分布式的调度任务,有良好的监听机制,和控制台,下面的案例也就冲这个图解来。

3、分片管理

这个概念在ElasticJob中是最具有特点的,实用性极好。

  • 分片概念

任务的分布式执行,需要将一个任务拆分为多个独立的任务项,然后由分布式的服务器分别执行某一个或几个分片项。

场景描述:假设有服务3台,分3片管理,要处理数据表100条,那就可以100%3,按照余数0,1,2分散到三台服务上执行,看到这里分库分表的基本逻辑涌上心头,这就是为何很多大牛讲说,编程思维很重要。

  • 个性化参数

个性化参数即shardingItemParameter,可以和分片项匹配对应关系,用于将分片项的数字转换为更加可读的业务代码。

场景描述:这里猛一读好像很飘逸,其实就是这个意思,如果分3片,取名[0,1,2]不好看,或者不好标识,可以分别给个别名标识一下,[0=A,1=B,2=C]。

二、定时任务加载

1、核心依赖包

这里使用2.0+的版本。

<dependency>
<groupId>com.dangdang</groupId>
<artifactId>elastic-job-lite-core</artifactId>
<version>2.1.5</version>
</dependency>
<dependency>
<groupId>com.dangdang</groupId>
<artifactId>elastic-job-lite-spring</artifactId>
<version>2.1.5</version>
</dependency>

2、核心配置文件

这里主要配置一下Zookeeper中间件,分片和分片参数。

zookeeper:
server: 127.0.0.1:2181
namespace: es-job job-config:
cron: 0/10 * * * * ?
shardCount: 1
shardItem: 0=A,1=B,2=C,3=D

3、自定义注解

看了官方的案例,没看到好用的注解,这里只能自己编写一个,基于案例的加载过程和核心API作为参考。

核心配置类:

com.dangdang.ddframe.job.lite.config.LiteJobConfiguration

根据自己想如何使用注解的思路,比如我只想注解定时任务名称和Cron表达式这两个功能,其他参数直接统一配置(这里可能是受QuartJob影响太深,可能根本就是想省事...)

@Inherited
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface TaskJobSign { @AliasFor("cron")
String value() default ""; @AliasFor("value")
String cron() default ""; String jobName() default ""; }

4、作业案例

这里打印一些基本参数,对照配置和注解,一目了然。

@Component
@TaskJobSign(cron = "0/5 * * * * ?",jobName = "Hello-Job")
public class HelloJob implements SimpleJob { private static final Logger LOG = LoggerFactory.getLogger(HelloJob.class.getName()) ; @Override
public void execute(ShardingContext shardingContext) {
LOG.info("当前线程: "+Thread.currentThread().getId());
LOG.info("任务分片:"+shardingContext.getShardingTotalCount());
LOG.info("当前分片:"+shardingContext.getShardingItem());
LOG.info("分片参数:"+shardingContext.getShardingParameter());
LOG.info("任务参数:"+shardingContext.getJobParameter());
}
}

5、加载定时任务

既然自定义注解,那加载过程自然也要自定义一下,读取自定义的注解,配置化,加入容器,然后初始化,等着任务执行就好。

@Configuration
public class ElasticJobConfig { @Resource
private ApplicationContext applicationContext ;
@Resource
private ZookeeperRegistryCenter zookeeperRegistryCenter; @Value("${job-config.cron}") private String cron ;
@Value("${job-config.shardCount}") private int shardCount ;
@Value("${job-config.shardItem}") private String shardItem ; /**
* 配置任务监听器
*/
@Bean
public ElasticJobListener elasticJobListener() {
return new TaskJobListener();
}
/**
* 初始化配置任务
*/
@PostConstruct
public void initTaskJob() {
Map<String, SimpleJob> jobMap = this.applicationContext.getBeansOfType(SimpleJob.class);
Iterator iterator = jobMap.entrySet().iterator();
while (iterator.hasNext()) {
// 自定义注解管理
Map.Entry<String, SimpleJob> entry = (Map.Entry)iterator.next();
SimpleJob simpleJob = entry.getValue();
TaskJobSign taskJobSign = simpleJob.getClass().getAnnotation(TaskJobSign.class);
if (taskJobSign != null){
String cron = taskJobSign.cron() ;
String jobName = taskJobSign.jobName() ;
// 生成配置
SimpleJobConfiguration simpleJobConfiguration = new SimpleJobConfiguration(
JobCoreConfiguration.newBuilder(jobName, cron, shardCount)
.shardingItemParameters(shardItem).jobParameter(jobName).build(),
simpleJob.getClass().getCanonicalName());
LiteJobConfiguration liteJobConfiguration = LiteJobConfiguration.newBuilder(
simpleJobConfiguration).overwrite(true).build();
TaskJobListener taskJobListener = new TaskJobListener();
// 初始化任务
SpringJobScheduler jobScheduler = new SpringJobScheduler(
simpleJob, zookeeperRegistryCenter,
liteJobConfiguration, taskJobListener);
jobScheduler.init();
}
}
}
}

絮叨一句:不要疑问这些API是怎么知道,看下官方文档的案例,他们怎么使用这些核心API,这里就是照着写过来,就是多一步自定义注解类的加载过程。当然官方文档大致读一遍还是很有必要的。

补刀一句:如何快速学习一些组件的用法,首先找到官方文档,或者开源库Wiki,再不济ReadMe文档(如果都没有,酌情放弃,另寻其他),熟悉基本功能是否符合自己的需求,如果符合,就看下基本用法案例,熟悉API,最后就是研究自己需要的功能模块,个人经验来看,该过程是弯路最少,坑最少的。

6、任务监听

用法非常简单,实现ElasticJobListener接口。

@Component
public class TaskJobListener implements ElasticJobListener {
private static final Logger LOG = LoggerFactory.getLogger(TaskJobListener.class); private long beginTime = 0; @Override
public void beforeJobExecuted(ShardingContexts shardingContexts) {
beginTime = System.currentTimeMillis();
LOG.info(shardingContexts.getJobName()+"===>开始...");
} @Override
public void afterJobExecuted(ShardingContexts shardingContexts) {
long endTime = System.currentTimeMillis();
LOG.info(shardingContexts.getJobName()+
"===>结束...[耗时:"+(endTime - beginTime)+"]");
}
}

絮叨一句:before和after执行前后,中间执行目标方法,标准的AOP切面思想,所以底层水平决定了对上层框架的理解速度,那本《Java编程思想》上的灰尘是不是该擦擦?

三、动态添加

1、作业任务

有部分场景需要动态添加和管理定时任务,基于上面的加载流程,在自定义一些步骤就可以。

@Component
public class GetTimeJob implements SimpleJob { private static final Logger LOG = LoggerFactory.getLogger(GetTimeJob.class.getName()) ; private static final SimpleDateFormat format =
new SimpleDateFormat("yyyy-MM-dd HH:mm:ss") ; @Override
public void execute(ShardingContext shardingContext) {
LOG.info("Job Name:"+shardingContext.getJobName());
LOG.info("Local Time:"+format.format(new Date()));
}
}

2、添加任务服务

这里就动态添加上面的任务。

@Service
public class TaskJobService { @Resource
private ZookeeperRegistryCenter zookeeperRegistryCenter; public void addTaskJob(final String jobName,final SimpleJob simpleJob,
final String cron,final int shardCount,final String shardItem) {
// 配置过程
JobCoreConfiguration jobCoreConfiguration = JobCoreConfiguration.newBuilder(
jobName, cron, shardCount)
.shardingItemParameters(shardItem).build();
JobTypeConfiguration jobTypeConfiguration = new SimpleJobConfiguration(jobCoreConfiguration,
simpleJob.getClass().getCanonicalName());
LiteJobConfiguration liteJobConfiguration = LiteJobConfiguration.newBuilder(
jobTypeConfiguration).overwrite(true).build();
TaskJobListener taskJobListener = new TaskJobListener();
// 加载执行
SpringJobScheduler jobScheduler = new SpringJobScheduler(
simpleJob, zookeeperRegistryCenter,
liteJobConfiguration, taskJobListener);
jobScheduler.init();
} }

补刀一句:这里添加之后,任务就会定时执行,如何停止任务又是一个问题,可以在任务名上做一些配置,比如在数据库生成一条记录[1,job1,state],如果调度到state为停止状态的任务,直接截胡即可。

3、测试接口

@RestController
public class TaskJobController { @Resource
private TaskJobService taskJobService ; @RequestMapping("/addJob")
public String addJob(@RequestParam("cron") String cron,@RequestParam("jobName") String jobName,
@RequestParam("shardCount") Integer shardCount,
@RequestParam("shardItem") String shardItem) {
taskJobService.addTaskJob(jobName, new GetTimeJob(), cron, shardCount, shardItem);
return "success";
}
}

四、源代码地址

GitHub·地址
https://github.com/cicadasmile/middle-ware-parent
GitEE·地址
https://gitee.com/cicadasmile/middle-ware-parent

SpringBoot2 整合ElasticJob框架,定制化管理流程的更多相关文章

  1. monkeyscript - 定制化monkey流程

    作为移动端测试必须掌握的初级Android稳定性工具:monkey,提到它时,脑海里一般涌现出两句话: 1.我会用,很简单 就是一行命令,一回车就开始跑起来了 2.使用问题多,不好用 太随机,很多操作 ...

  2. SpringBoot2 整合JTA组件,多数据源事务管理

    本文源码:GitHub·点这里 || GitEE·点这里 一.JTA组件简介 1.JTA基本概念 JTA即Java-Transaction-API,JTA允许应用程序执行分布式事务处理,即在两个或多个 ...

  3. SpringBoot2 整合MinIO中间件,实现文件便捷管理

    本文源码:GitHub·点这里 || GitEE·点这里 一.MinIO简介 1.基础描述 MinIO是一个开源的对象存储服务.适合于存储大容量非结构化的数据,例如图片.视频.日志文件.备份数据和容器 ...

  4. SpringBoot2 整合Ehcache组件,轻量级缓存管理

    本文源码:GitHub·点这里 || GitEE·点这里 一.Ehcache缓存简介 1.基础简介 EhCache是一个纯Java的进程内缓存框架,具有快速.上手简单等特点,是Hibernate中默认 ...

  5. 定制化移动办公APP:打造企业专属的“钉钉”“纷享销客”,实现企业办公管理一体化

    一.项目背景 随着信息化社会的高速发展,市场竞争日益激烈,传统的管理和办公系统多且复杂,用户需要使用多个系统才可完成一项工作,而且各个系统的界面和风格存在差异,造成了信息查找不便,大大降低了用户的工作 ...

  6. SpringBoot2.0 基础案例(10):整合Mybatis框架,集成分页助手插件

    一.Mybatis框架 1.mybatis简介 MyBatis 是一款优秀的持久层框架,它支持定制化 SQL.存储过程以及高级映射.MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获 ...

  7. SpringBoot2 整合Kafka组件,应用案例和流程详解

    本文源码:GitHub·点这里 || GitEE·点这里 一.搭建Kafka环境 1.下载解压 -- 下载 wget http://mirror.bit.edu.cn/apache/kafka/2.2 ...

  8. SpringBoot2.0 整合 SpringSecurity 框架,实现用户权限安全管理

    本文源码:GitHub·点这里 || GitEE·点这里 一.Security简介 1.基础概念 Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方 ...

  9. (十三)整合 SpringSecurity 框架,实现用户权限管理

    整合 SpringSecurity 框架,实现用户权限管理 1.Security简介 1.1 基础概念 1.2 核心API解读 2.SpringBoot整合SpringSecurity 2.1 流程描 ...

随机推荐

  1. iOS传感器集锦、飞机大战、开发调试工具、强制更新、Swift仿QQ空间头部等源码

    iOS精选源码 飞机大作战 MUPhotoPreview -简单易用的图片浏览器 LLDebugTool是一款针对开发者和测试者的调试工具,它可以帮... 多个UIScrollView.UITable ...

  2. 吴裕雄 python 神经网络——TensorFlow 卷积神经网络手写数字图片识别

    import os import tensorflow as tf from tensorflow.examples.tutorials.mnist import input_data INPUT_N ...

  3. VisionPro和Halcon的详细对比

    一.概括的对比 1.1  Halcon的优势 Halcon有着更加低廉的Lisence 1.并且提供更好.更强大的2D和3D的视觉软件库 2.Halcon支持的视觉图像采集设备数量是Visionpro ...

  4. C++ new和delete运算符简介

    在C语言中,动态分配内存用 malloc() 函数,释放内存用 free() 函数.如下所示: ); //分配10个int型的内存空间 free(p); //释放内存 在C++中,这两个函数仍然可以使 ...

  5. python数据类型:Number数字

    Python Number数据类型用于存储数值 数据类型是不允许改变的,如果改变Number数据类型的值,将从新分配内存空间 整型(int):整型或整数,是正或者负整数,不带小数点 长整型(long) ...

  6. django框架基础-ORM跨表操作-长期维护

    ###############    一对一跨表查询    ################ import os if __name__ == '__main__': os.environ.setde ...

  7. mysql表关联问题(第一卷:外键1对多之1)

    表关联的问题在开发中是必不可少的,现在我先简单的谈谈我的学习经验.先来说一下外键一对多的问题. 步骤1:准备数据: (1)设计模拟场景: 一个游戏为了测试游戏的运行情况,招来了一批用户来试玩,现需要录 ...

  8. 图论初步-Tarjan算法及其应用

    暑假刷了一堆Tarjan题到头来还是忘得差不多. 这篇博客权当复习吧. 一些定义 无向图 割顶与桥 (划重点) 图G是连通图,删除一个点表示删除此点以及所有与其相连的边. 若删除某点u后G不再连通,那 ...

  9. LG_2051_[AHOI2009]中国象棋

    题目描述 这次小可可想解决的难题和中国象棋有关,在一个N行M列的棋盘上,让你放若干个炮(可以是0个),使得没有一个炮可以攻击到另一个炮,请问有多少种放置方法.大家肯定很清楚,在中国象棋中炮的行走方式是 ...

  10. 吴裕雄--天生自然python编程:pycharm常用快捷键问题

    最近在使用pycharm的时候发现不能正常使用ctrl+c/v进行复制粘贴,也无法使用tab键对大段代码进行整体缩进.后来发现是因为安装了vim插件的问题,在setting里找到vim插件,取消勾选即 ...