JAVA定时任务

利用ThreadPoolTaskScheduler构建业务框架实现定时任务

在日常办公中,我们总是会有业务需求去使用到定时任务,通常情况下会将触发的模块独立出来,行程一个独立的任务进行管理。在以前的项目中,涉及到定时任务的模块,我们通常都是用spring提供的@Scheduled来实现。那么如果我们不使用注解应该如何实现呢?日常研究同事的优秀代码,昏沉的下午,不如花点时间来总结一下现在业务对这一块的实现,也是对自己工作状态的一个调整。

ThreadPoolTaskScheduler 类的介绍

ThreadPoolTaskScheduler是存在于org.springframework.scheduling.concurrent包下,是spring TaskScheduler 接口的一个实现。该类提供了大量的重载方法进行任务调度。

定时任务主要用到了public ScheduledFuture<?> schedule(Runnable task, Trigger trigger)方法
方法描述
当trigger对应的时间,触发提交的Runnable的run方法。如果出现异常将会停止本次执行,并将执行结构提交给ScheduledFuture

CronTrigger 类的介绍

CronTrigger类位于org.springframework.scheduling.support包下,是Trigger接口的实现,调度规则给予Crone表达式,能够提供比 SimpleTrigger 更有具体实际意义的调度方案。CronTrigger 支持日历相关的重复时间间隔(比如每月第一个周一执行),而不是简单的周期时间间隔。

首先自定义了一个定时任务的模型 ScheduledTask

定义了三个参数:

volatile ScheduledFuture<?> future; //存放执行后的结果
private String cron;  //存放定时任务
private Runnable runnable;  //要执行的业务逻辑存放

定义一个抽象的任务 AbstractTask.class

当业务中,很多定时任务有共同的特性时,可以利用模版设备模式,定义好模板,在各自的实现中,去实现具体的逻辑。
在抽象类中定义了如下公共类

1.用于模版扭转的run方法

public void run() {
      long start = System.currentTimeMillis();
      Logger logger = getLogger();
      String taskName = taskName();
      logger.info("{}:开始执行", taskName);
      handleTask();
      long end = System.currentTimeMillis();
      logger.info("{}:执行结束,耗时:{}", taskName, (end - start));
    }

2.由各个具体实现类依据自己的业务逻辑来完成实现

public abstract void handleTask();

3.统一的数据返回的处理接口
4.获取任务名称的方法

public String taskName() {
        return this.getClass().getSimpleName();
    }

5.获取Cron 触发表达式的接口,由各个具体实现类实现

public abstract String getCron();

依据业务逻辑 继承AbstractTask.class

当然也可以依据类型的需要,再细化一下模版,比如以处理条目分类,分为单条操作抽象类 , 批量分页操作抽象类等。
可以从一下角度来设计

  1. 获取定时任务触发的crone表达式
  2. 获取到查询条件
  3. 执行条件的过程接口
  4. 获取到结果以后的统一处理

注意:需要将实现类 注意点spring容器中,在类上添加@Component

自定义一个初始化定时任务 ScheduledTaskHandler.class

该类主要负责将AbstractTask的执行进行初始化,将其中的run方法转换为Runnable的实现,将定时任务配置转换为CronTrigger的实现, 通过提前内置好的 ThreadPoolTaskScheduler schedulerPool 调用其 public ScheduledFuture<?> schedule(Runnable task, Trigger trigger) 方法,实现定时任务工能的执行。

核心逻辑(伪代码):

//一个提前内置好的 schedulerPool
@Autowired
private ThreadPoolTaskScheduler schedulerPool;

.....

{
	.....
	//获取到spring容器中所有注入的AbstractTask.class子类的bean
	Map<String, AbstractTask> abstractTaskMap = applicationContext.getBeansOfType(AbstractTask.class);
	//循环处理
	for (AbstractTask task : abstractTasks) {
	   String taskName = task.taskName();
	   int taskIndex = INDEX.getAndIncrement();
	   addTask(taskName, new ScheduledTask(task.getCron(), () -> {task.run()}), task.ifAddTaskHandlePool());
	}
}

.....

//addTask方法,将其调用schedulerPool.schedule
public void addTask(String taskName, ScheduledTask scheduledTask, boolean ifAddTaskHandlePool) {
	if (ifAddTaskHandlePool) {
	      ScheduledFuture future = schedulerPool.schedule(scheduledTask.getRunnable(), new CronTrigger(scheduledTask.getCron()));
	      scheduledTask.setFuture(future);
	      SCHEDULED_TASKS.put(taskName, scheduledTask);
	  }
}

注:其中有时候为了提交系统的性能,我们也许会通过zk调度,或者通过其他方式,就可以在ScheduledTaskHandler调度的过程中对其进行控制。

提供Controller,增加补偿机制

定时任务如果出现意外,或者临时的需求变化,有时候需要调整执行时间,或者额外执行,就可以对外提供API进行处理,通过上述的方式,我们可以通过AbstractTask类的实现类的bean名称,获取到实例,直接调用该实例实现的handleTask()方法 。

总结

当项目中有很多通用的业务逻辑处理,比如流程、工单或者数据库同步等很多可以抽象出来的东西,尽量抽象出来,日后当有新的相同的实现出现,我们仅需继承,去实现该业务本身的逻辑,而无需重复编写扭转的框架内容。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值