引言
在企业开发中,经常会遇到时间任务调度的需求,比如每天凌晨生成前天报表、数据汇总等动态配置是否开启定时的任务。在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 在简单任务下也是一个不错的选择。