最近工作上接到了一个定时相关的需求,通过分析发现,需求比较简单,并不需要任务持久化,也不需要定时任务的复杂操作。
所以对比之下,选用了spring-context模块里包含的scheduling功能。
令人兴奋的是!基于spring-boot的自动配置,选用相关两个注解便把我从定时调度功能解脱出来,专心于业务功能的开发了。
像这样:
- 首先在启动类或者配置类上,启用spring的定时调度,添加注解@EnableScheduling
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;
/**
* Created by lujiu on 2018/11/25.
*/
@EnableScheduling
@SpringBootApplication
public class TransApplication {
public static void main(String[] args) {
SpringApplication.run(TransApplication.class, args);
}
}
- 然后,在业务功能上使用@Scheduled,即可很方便的把所修饰的业务功能与一对应的触发器捆绑注册到spring的调度任务列表中(spring会根据调度任务类型的不同,分别添加到不同的列表中,以方便任务的触发执行)
源码属性部分
public class ScheduledTaskRegistrar implements InitializingBean, DisposableBean {
private TaskScheduler taskScheduler;
private ScheduledExecutorService localExecutor;
private List<TriggerTask> triggerTasks;
private List<CronTask> cronTasks;
private List<IntervalTask> fixedRateTasks;
private List<IntervalTask> fixedDelayTasks;
private final Map<Task, ScheduledTask> unresolvedTasks = new HashMap(16);
private final Set<ScheduledTask> scheduledTasks = new LinkedHashSet(16);
... ...
}
可以发现@Scheduled的三种类型的定时调度分别被暂存,因为需求这里我只关心cron表达式相关的配置。其余两个固定频率和固定间隙,大家有兴趣可以在文末联系我,再做讨论。
如果,你的需求只是静态cron定时调度的话,恭喜老兄,你的工作已经完成了99%,只需要最后一个潇洒的简单注解:
//此处cron表达式仅做示例
@Scheduled(cron="0 0 0 * * ? ")
public void exec() {
//业务功能
}
大功告成!
可惜,我的需求不是,我需要动态cron。还能怎么办,继续干呗!(笑哭脸)
翻翻spring手册,问问度娘。
说到这忍不住吐槽下技术分享环境,度娘一波下来,十篇博文,六篇内容都是几乎相同的。分享优秀的文章我也可以理解,但是分享之前能不能自己先分析下呢?根本就没道理的东西,有什么好传播的。
- 从ScheduledTaskRegistrar中注意到了TriggerTask这个东西,主要是它这个名字比较吸引眼球,用过Quartz的应该都知道,与之同名组件是触发Quartz中Job用的。
其实,目前感觉spring的schedule和Quartz差不多,相当于轻量级Quartz。定时任务的持久化,麻烦一点用spring也可以完成。
言归正传!
- 在ScheduledTaskRegistrar添加Trigger类型任务列表,需要构建一个TriggerTask,包含任务线程和触发器,任务线程内包含具体的业务功能,触发器内就可以灵活的设置cron表达式,可以用配置文件,数据库,REST服务调用传参等等。
具体代码如下:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.Trigger;
import org.springframework.scheduling.TriggerContext;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.stereotype.Component;
import java.util.Date;
/**
* Created by lujiu on 2018/11/26.
*/
@Component
@EnableScheduling
public class DynamicCronSchedule implements SchedulingConfigurer{
private static Logger logger = LoggerFactory.getLogger(DynamicCronSchedule.class);
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
Runnable task = new Runnable() {
@Override
public void run() {
//业务执行代码
}
};
Trigger trigger = new Trigger() {
@Override
public Date nextExecutionTime(TriggerContext triggerContext) {
//执行于每一次任务的触发
String cron = "这里就可以随意设置你的数据源咯";
logger.info("cron expression is [{}]",cron);
logger.info("trigger list size is [{}]",taskRegistrar.getTriggerTaskList().size());
CronTrigger cronTrigger = new CronTrigger(cron);
Date nextExecTime = cronTrigger.nextExecutionTime(triggerContext);
return nextExecTime;
}
};
taskRegistrar.addTriggerTask(task, trigger);
}
}