时间:2021-05-19
之前公司经常会遇到配置定时任务,简单的任务可以直接依赖spring。
简单任务直接使用 @scheduled 注解配合@EnableScheduling。
但是如何实现简单的动态cron呢?
开发原则:
尽可能在项目本身去实现,少依赖第三方框架,避免项目过于臃肿和复杂。
俩种任务调度方式:
springBoot 基础模块 spring-boot-starter-web 已经内置 schedule ,无需引入额外依赖。
先思考几个问题:
1、动态 cron 实现的原理
任务的 【 停止】是基于 future接口 的cancel() 方法。
任务的 【增加、删除、启动】是基于 注册到 类ScheduledTaskRegistrar 的 ScheduledFuture的数量。
涉及核心类:
2、多任务并行执行配置
spring默认机制对schedule是单线程,需要配置多线程并行执行。
3、如何配置多个任务
好多博文,都是配置一个cron,这让初学者很难受。
4、如何配置任务分组
根据自己业务背景,可根据步骤三,进行改造。
5、如何配置服务启动自启任务。
想要程序启动时首次去加我们设置的task,只需实现 CommandLineRunner 即可。
6、如何从数据库读取配置
这个其实很简单,在实现 ScheduledTaskRegistrar 时,先直接查询我们需要的数据即可。
7、如何优雅的实现我们的代码
这里为了我们多个task实现时,去除臃肿的if else ,使用策略模式去实现我们的task,这里代码里面会具体介绍。
参考类图:
8、如何去触发我们的schedule 【增删启停】
配置好 task任务类,注入到 controller ,通过接口直接调用即可。
先贴出我的github 代码,下面代码描述不全。
1.1 对应数据库的实体类 TaskEntity
@Data@AllArgsConstructor@NoArgsConstructorpublic class TaskEntity { /** * 任务id */ private int taskId; /** * 任务说明 */ private String desc; /** * cron 表达式 */ private String expression;}1.2 配置每个任务实现
配置任务接口 TaskService
public interface TaskService { void HandlerJob(); Integer jobId();}配置任务接口实现 TaskServiceJob1Impl、TaskServiceJob2Impl …
@Servicepublic class TaskServiceJob1Impl implements TaskService { @Override public void HandlerJob() { System.out.println("------job1 开始执行---------:"+new Date()); System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()) + " " + Thread.currentThread().getName() + " 任务一启动"); try { Thread.sleep(10000);//任务耗时10秒 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()) + " " + Thread.currentThread().getName() + " 结束"); } @Override public Integer jobId() { return 1; }}1.3 配置任务解析器 TaskSolverChooser
注:
这里引入策略模式
为啥要配置 任务解析器选择器:
因为我们实现多个任务时,一个任务对应一个 CronTask,需要在 MyScheduledTask 里面去实现我们每一个方法。
譬如,我们有100个任务就要自定义100个任务实现方法,代码会很臃肿,明显不符合,【开闭原则】,于是这里采用策略模式,解耦我们多个任务业务实现逻辑。
1.4 配置MyScheduledTask (动态cron核心配置)
说明:
1、配置多线程执行任务
2、配置 刷新 task
3、配置 停止 task
4、配置 执行task 业务逻辑
1.5 配置程序启动时首次去加我们设置的task
@Componentpublic class StartInitTask implements CommandLineRunner { @Autowired private MyScheduledTask myScheduledTask; @Override public void run(String... args) throws Exception { List<TaskEntity> list = Arrays.asList( new TaskEntity(1, "测试1", "0/1 * * * * ?"), new TaskEntity(2, "测试2", "0/1 * * * * ?") ); myScheduledTask.refresh(list); }}1.6 配置web接口去触发,增删启停
@RestControllerpublic class StartController { @Autowired private MyScheduledTask scheduledTask; @PostMapping(value = "/startOrChangeCron") public String changeCron(@RequestBody List<TaskEntity> list){ if (CollectionUtils.isEmpty(list)) { // 这里模拟存在数据库的数据 list = Arrays.asList( new TaskEntity(1, "测试1","0/1 * * * * ?") , new TaskEntity(2, "测试2","0/1 * * * * ?") ); } scheduledTask.refresh(list); return "task任务:" + list.toString() + "已经开始运行"; } @PostMapping(value = "/stopCron") public String stopCron(@RequestBody List<TaskEntity> list){ if (CollectionUtils.isEmpty(list)) { // 这里模拟将要停止的cron可通过前端传来 list = Arrays.asList( new TaskEntity(1, "测试1","0/1 * * * * ?") , new TaskEntity(2, "测试2","0/1 * * * * ?") ); } scheduledTask.stop(list); List<Integer> collect = list.stream().map(TaskEntity::getTaskId).collect(Collectors.toList()); return "task任务:" + collect.toString() + "已经停止启动"; }}实现原理:
基于反射实现,根据方法全类名,去动态执行方法。多任务分组配置,根据任务类型进行分组。
eg:
定时任务人员的相关操作,有检测人员离职状态,人员业绩达标,人员考勤…等,
作用:
对人员定时任务做一个分类,在同一个类里面去实现不同的task,
比较
《1. 普通多任务动态cron 实现》,是一个类可以实现一个task
《2. 分组多任务动态cron 实现》,是一个类可以实现多个task
详细可参考: 分组多任务动态cron
测试1项目启动自启
TaskServiceJob1Impl和TaskServiceJob1Impl … 设置 阻塞10s
观察日志时间可发现,已经同时并发执行俩个任务。
测试2 触发 刷新【增、删、启】我们的task,。
其实这里没这么智能,如果需要触发刷新接口,实际上是重新加载我们的task,就是对应触发我们,增加任务任务,删除任务,启动任务。
使用idea插件测试接口
观察日志
测试3 触发 停止接口,停止一个接口。
这里测试略过…
其实实现简单的动态配置,以上代码可用,比较简单。
到此这篇关于spring schedule配置多任务动态cron(增删启停)的文章就介绍到这了,更多相关spring schedule 多任务动态cron内容请搜索以前的文章或继续浏览下面的相关文章希望大家以后多多支持!
声明:本页内容来源网络,仅供用户参考;我单位不保证亦不表示资料全面及准确无误,也不保证亦不表示这些资料为最新信息,如因任何原因,本网内容或者用户因倚赖本网内容造成任何损失或损害,我单位将不会负任何法律责任。如涉及版权问题,请提交至online#300.cn邮箱联系删除。
通常在使用java实现定时任务时,有两种方法,一种是spring中的schedule(cron="*/5***?"),另一种就是java中的timer,
一,介绍与需求1.1,介绍定时任务(node-schedule),是针对Node.js的一种灵活的cron-like和not-cron-like作业调度程序。它
前言众所周知在spring3.0版本后,自带了一个定时任务工具,而且使用简单方便,不用配置文件,可以动态改变执行状态。也可以使用cron表达式设置定时任务。被执
我以为动态停启定时任务一般用quartz,没想到还可以通过ScheduledTaskRegistrar来拓展。但是分布式场景,建议还是用quartz吧!在spr
记录下Spring自带的定时任务用法。spring中使用定时任务基于xml配置文件使用定时任务首先配置spring开启定时任务