本文于 1502 天之前发表,文中内容可能已经过时。
引言
在企业开发中,经常会遇到时间任务调度的需求,比如每天凌晨生成前天报表、数据汇总等动态配置是否开启定时的任务。在 Java 领域中,定时任务的开源工具也非常多,小到一个 Timer 类,大到 Quartz 框架。在 Spring 中最常见的定时任务方式属 Spring schedule 注解的方式和利用 Quartz 动态管理定时任务。总体来说,个人比较喜欢的还是 Quartz,功能强大而且使用方便。
Spring-@scheduled
对于较简单的任务可以使用 Spring 内置的定时任务方法 @scheduled 注解进行配置达到自己的需求。
spring 配置文件
配置 spring 项目的基础文件 spring.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| <?xml version="1.0" encoding="UTF-8"?> <beans xmlns:task="http://www.springframework.org/schema/task" xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.1.xsd"> <task:executor id="executor" pool-size="5" /> <task:scheduler id="scheduler" pool-size="10" /> <task:annotation-driven executor="executor" scheduler="scheduler" /> </beans>
|
Task 任务类
定义了一个任务类 ATask,里面有两个定时任务 aTask 和 bTask。编写 java 业务代码,需要在类声明上边添加 **@Component 注解,并在需要定时任务执行的方法声明上添加 @Scheduled** 注解以及 cron 表达式和相关的参数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| @Component public class ATask {
@Scheduled(cron = "0/10 * * * * ? ") public void aTask() { DateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); System.out.println(sdf.format(DateTime.now().toDate()) + "*********A任务每10秒执行一次进入测试"); }
@Scheduled(cron = "0/5 * * * * ? ") public void bTask() { DateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); System.out.println(sdf.format(DateTime.now().toDate()) + "*********B任务每5秒执行一次进入测试"); } }
|
运行结果
启动项目会发现定时任务已经开启。
Spring-Quartz
@scheduled 固然可以实现定时任务,但是仔细想想并不灵活,任务随着应用的启动而执行,并不能动态的进行管理,很是不方便,然而 Quartz 很好的解决了这一问题。
引入依赖
1 2 3 4 5
| <dependency> <groupId>org.quartz-scheduler</groupId> <artifactId>quartz</artifactId> <version>2.2.1</version> </dependency>
|
任务管理类 QuartzManager
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
| public class QuartzManager {
private static SchedulerFactory schedulerFactory = new StdSchedulerFactory();
@SuppressWarnings({ "unchecked", "rawtypes" }) public static void addJob(String jobName, String jobGroupName, String triggerName, String triggerGroupName, Class jobClass, String cron) { try { Scheduler sched = schedulerFactory.getScheduler(); JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(jobName, jobGroupName).build();
TriggerBuilder<Trigger> triggerBuilder = TriggerBuilder.newTrigger(); triggerBuilder.withIdentity(triggerName, triggerGroupName); triggerBuilder.startNow(); triggerBuilder.withSchedule(CronScheduleBuilder.cronSchedule(cron)); CronTrigger trigger = (CronTrigger) triggerBuilder.build();
sched.scheduleJob(jobDetail, trigger);
if (!sched.isShutdown()) { sched.start(); } } catch (Exception e) { throw new RuntimeException(e); } }
public static void modifyJobTime(String jobName, String jobGroupName, String triggerName, String triggerGroupName, String cron) { try { Scheduler sched = schedulerFactory.getScheduler(); TriggerKey triggerKey = TriggerKey.triggerKey(triggerName, triggerGroupName); CronTrigger trigger = (CronTrigger) sched.getTrigger(triggerKey); if (trigger == null) { return; }
String oldTime = trigger.getCronExpression(); if (!oldTime.equalsIgnoreCase(cron)) { TriggerBuilder<Trigger> triggerBuilder = TriggerBuilder.newTrigger(); triggerBuilder.withIdentity(triggerName, triggerGroupName); triggerBuilder.startNow(); triggerBuilder.withSchedule(CronScheduleBuilder.cronSchedule(cron)); trigger = (CronTrigger) triggerBuilder.build(); sched.rescheduleJob(triggerKey, trigger);
} } catch (Exception e) { throw new RuntimeException(e); } }
public static void removeJob(String jobName, String jobGroupName, String triggerName, String triggerGroupName) { try { Scheduler sched = schedulerFactory.getScheduler();
TriggerKey triggerKey = TriggerKey.triggerKey(triggerName, triggerGroupName);
sched.pauseTrigger(triggerKey); sched.unscheduleJob(triggerKey); sched.deleteJob(JobKey.jobKey(jobName, jobGroupName)); } catch (Exception e) { throw new RuntimeException(e); } }
public static void startJobs() { try { Scheduler sched = schedulerFactory.getScheduler(); sched.start(); } catch (Exception e) { throw new RuntimeException(e); } }
public static void shutdownJobs() { try { Scheduler sched = schedulerFactory.getScheduler(); if (!sched.isShutdown()) { sched.shutdown(); } } catch (Exception e) { throw new RuntimeException(e); } } }
|
任务执行业务
这里做一个简单的演示,只实现 Job 接口打印当前时间。
1 2 3 4 5 6 7
| public class MyJob implements Job{
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { DateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); System.out.println(sdf.format(DateTime.now().toDate())); } }
|
测试动态定时任务
新建 QuartzTest.Java 测试类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| public class QuartzTest { public static String JOB_NAME = "动态任务调度"; public static String TRIGGER_NAME = "动态任务触发器"; public static String JOB_GROUP_NAME = "XLXXCC_JOB_GROUP"; public static String TRIGGER_GROUP_NAME = "XLXXCC_JOB_GROUP";
public static void main(String[] args) { try { System.out.println("【系统启动】开始(每1秒输出一次)..."); QuartzManager.addJob(JOB_NAME, JOB_GROUP_NAME, TRIGGER_NAME, TRIGGER_GROUP_NAME, MyJob.class,"0/1 * * * * ?");
Thread.sleep(5000); System.out.println("【修改时间】开始(每5秒输出一次)..."); QuartzManager.modifyJobTime(JOB_NAME, JOB_GROUP_NAME, TRIGGER_NAME, TRIGGER_GROUP_NAME, "0/5 * * * * ?");
Thread.sleep(15000); System.out.println("【移除定时】开始..."); QuartzManager.removeJob(JOB_NAME, JOB_GROUP_NAME, TRIGGER_NAME, TRIGGER_GROUP_NAME); System.out.println("【移除定时】成功"); } catch (Exception e) { e.printStackTrace(); } } }
|
输出如下:
总结
通过以上测试可以明显的看出两者的优劣,Quartz 足够灵活强大,但 Spring scheduled 在简单任务下也是一个不错的选择。