【spring配置】——spring整合Quartz定时器

第一种:为普通java类中的某个方法配置跑批任务

  1. MethodInvokingJobDetailFactoryBean
  2. CronTriggerBean
  3. SchedulerFactoryBean

1.定义要跑批的类和方法:

  1. package com.xy.utils.quartz;
  2. import org.joda.time.DateTime;
  3. import org.slf4j.Logger;
  4. import org.slf4j.LoggerFactory;
  5. /**
  6. * 测试定时器类
  7. * @author javaw
  8. *
  9. */
  10. public class TestQuartz {
  11. public static Logger logger = LoggerFactory.getLogger(TestQuartz.class);
  12. public void TestMethod(){
  13. logger.info("Auto Execute TestMethod start! Date={}" ,new DateTime().toString("YYYY-MM-DD HH:mm:ss" ));
  14. logger.info("**********测试跑批类************");
  15. logger.info("Auto Execute TestMethod end! Date={}" ,new DateTime().toString("YYYY-MM-DD HH:mm:ss" ));
  16. }
  17. }

2.配置Spring定时器让quartz自动执行testMethod方法:

  1. <!-- 实例化bean -->
  2. <bean id= "testMethodQuartz" class ="com.xy.utils.quartz.TestQuartz"/>
  3. <!-- 配置MethodInvokingJobDetailFactoryBean -->
  4. <bean id= "testTaskMethod"
  5. class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
  6. <property name="targetObject" ref="testMethodQuartz"/>
  7. <property name="targetMethod" value="TestMethod"/>
  8. <property name="concurrent" value="false"/>
  9. </bean>
  10. <!-- 配置定时表达式 -->
  11. <bean id= "testTaskTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean" >
  12. <property name="jobDetail" ref="testTaskMethod" />
  13. <!-- 每一分钟执行一次 -->
  14. <property name="cronExpression" value="0 0/1 * * * ?" />
  15. </bean>
  16. <!-- 配置调度工厂 -->
  17. <bean id= "testSchedulerFactoryBean"
  18. class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
  19. <property name="triggers" >
  20. <list>
  21. <ref bean="testTaskTrigger" />
  22. </list>
  23. </property>
  24. </bean>

3.写测试方法进行调用(不用启动tomcat):

  1. public static void main(String[] args) {
  2. SchedulerFactoryBean schedulerFactoryBean = (SchedulerFactoryBean) SpringUtilsFromClassPathXml.getBean( "testSchedulerFactoryBean");
  3. //启动调度器
  4. schedulerFactoryBean.start();
  5. }

第二种:为继承QuartzJobBean的java类配置跑批任务

1.写java类继承QuartzJobBean,重写executeInternal 方法:

  1. package com.xy.utils.quartz;
  2. import org.joda.time.DateTime;
  3. import org.quartz.JobExecutionContext;
  4. import org.quartz.JobExecutionException;
  5. import org.slf4j.Logger;
  6. import org.slf4j.LoggerFactory;
  7. import org.springframework.scheduling.quartz.QuartzJobBean;
  8. import org.springframework.scheduling.quartz.SchedulerFactoryBean;
  9. /**
  10. * 测试继承QuartzJobBean的java类配置定时器
  11. * @author javaw
  12. *
  13. */
  14. public class TestQuartzExtendsJobBean extends QuartzJobBean{
  15. private static Logger logger = LoggerFactory.getLogger(TestQuartzExtendsJobBean. class);
  16. @Override
  17. protected void executeInternal(JobExecutionContext context)
  18. throws JobExecutionException {
  19. logger.info("Auto Execute TestQuartzExtendsJobBean start! Date={}",new DateTime().toString( "YYYY-MM-DD HH:mm:ss"));
  20. logger.info("**********"+content.getMergedJobDataMap().get("descString")+"************");
  21. logger.info("Auto Execute TestQuartzExtendsJobBean end! Date={}",new DateTime().toString( "YYYY-MM-DD HH:mm:ss"));
  22. }
  23. }

2.配置文件:

  1. <!--
  2. 第二种:为继承Quartz的java类实现跑批
  3. **********1.JobDetailBean
  4. **********2.CronTriggerBean
  5. **********3.SchedulerFactoryBean
  6. -->
  7. <bean id= "testJobDetailBean"
  8. class="org.springframework.scheduling.quartz.JobDetailBean">
  9. <property name="name" value="exampleJob" />
  10. <property name="jobClass"
  11. value="com.xy.utils.quartz.TestQuartzExtendsJobBean"/>
  12. <!-- 可以封装各种数据到JobExecutionContext里 -->
  13. <property name="jobDataAsMap">
  14. <map>
  15. <entry key="descString" value="测试跑批"/>
  16. </map>
  17. </property>
  18. </bean >
  19. <bean id= "testTaskTrigger"
  20. class="org.springframework.scheduling.quartz.CronTriggerBean">
  21. <property name="jobDetail" ref="testJobDetailBean" />
  22. <property name="cronExpression" value="0 0/1 * * * ?" />
  23. </bean>
  24. <bean id= "testSchedulerFactoryBean"
  25. class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
  26. <property name="triggers" >
  27. <list>
  28. <ref bean="testTaskTrigger" />
  29. </list>
  30. </property>
  31. </bean>

第三种:定时任务持久化(JobDetailTx)

优势:

集群部署定时器通过故障切换和负载均衡的功能,提高调度器的可用性和扩展性。

本质:

集群上的所有节点通过共享一个数据库来来工作的。所有节点quartz通过启动两个维护线程来维护数据库状态实现集群管理,一个是检测节点状态线程,一个是恢复任务线程。一个 Quartz 集群中的每个节点是一个独立的 Quartz 应用,它又管理着其他的节点。

模式:

1.获取任务

负载均衡是自动完成的,集群的每个节点会尽快触发任务。当第一个节点获取到任务,会通过锁定,阻止其他线程获取到该任务。

2.故障切换

当一个节点执行任务失败(服务down掉或其他原因),其他节点会检测到并标识在失败节点上正在执行的数据库中的任务。任何标记为可恢复(任务详细里的requests recovery属性)的任务都会被其他节点继续执行。没有标记可恢复的任务会被释放掉。

  1. CREATE TABLE qrtz_job_details
  2. (
  3. ....
  4. JOB_NAME VARCHAR2(80) NOT NULL,
  5. JOB_GROUP VARCHAR2(80) NOT NULL,
  6. REQUESTS_RECOVERY VARCHAR2(1) NOT NULL, --可恢复标记
  7. );
  1. SchedulerFactoryBean
  2. JobDetail
  3. Trigger
  4. Job

将定时任务持久化可以解决分布式跑批的问题,避免服务器重启信息丢失。

定时任务定义需要实例化JobDetail和Trigger,然后使用Scheduler进行调度。这个需要使用到Quartz的jar包。

每个jar包创建任务的方式都不相同。具体需要查看官方api。

quartz2.2.1中给出的示例:

  1. JobDetail job = newJob(MyJob.class)
  2. .withIdentity("myJob")
  3. .build();
  4. Trigger trigger = newTrigger()
  5. .withIdentity(triggerKey("myTrigger", "myTriggerGroup"))
  6. .withSchedule(simpleSchedule()
  7. .withIntervalInHours(1)
  8. .repeatForever())
  9. .startAt(futureDate(10, MINUTES))
  10. .build();
  11. scheduler.scheduleJob(job, trigger);

导入jar包后,写如下测试类:

  1. package com.xy.utils.scheduler;
  2. import org.quartz.JobBuilder;
  3. import org.quartz.JobDetail;
  4. import org.quartz.Scheduler;
  5. import org.quartz.SchedulerFactory;
  6. import org.quartz.SimpleScheduleBuilder;
  7. import org.quartz.Trigger;
  8. import org.quartz.TriggerBuilder;
  9. import org.quartz.impl.StdSchedulerFactory;
  10. public class quartzTest {
  11. public static void main(String args[]) throws Exception {
  12. JobDetail jobDetail= JobBuilder.newJob(TestJob.class)
  13. .withIdentity("job","group")
  14. .build();
  15. Trigger trigger= TriggerBuilder.newTrigger().withIdentity("job","group").startNow().withSchedule(
  16. SimpleScheduleBuilder.simpleSchedule()
  17. .withIntervalInSeconds(10)   //时间间隔
  18. .withRepeatCount(10)        //重复次数n+1
  19. )
  20. .build();
  21. SchedulerFactory sf = new StdSchedulerFactory();
  22. Scheduler sched = sf.getScheduler();
  23. sched.scheduleJob(jobDetail, trigger);
  24. sched.start();
  25. }
  26. }

定时执行的任务类:

  1. package com.xy.utils.scheduler;
  2. import org.quartz.Job;
  3. import org.quartz.JobExecutionContext;
  4. import org.quartz.JobExecutionException;
  5. public class TestJob implements Job {
  6. public void execute(JobExecutionContext arg0) throws JobExecutionException {
  7. System.out.println("*****执行批处理任务******");
  8. }
  9. }

【spring配置】——spring整合Quartz定时器

这种任务并没有持久化到数据库中。

在Spring中配置SchedulerFactoryBean:

  1. <!--
  2. 第三种:从数据库中读取跑批任务(适合集群部署跑批)
  3. **********1.SchedulerFactoryBean
  4. -->
  5. <bean id="schedulerBeanFactory" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
  6. <!-- 注入数据源,包含任务执行表 -->
  7. <property name="dataSource" ref="dataSource"/>
  8. <!--applicationContextSchedulerContextKey:
  9. 把spring上下文以key/value的方式存放在了quartz的上下文中了,
  10. 可以用applicationContextSchedulerContextKey所定义的key得到对应的spring上下文-->
  11. <property name="applicationContextSchedulerContextKey" value="applicationContext"/>
  12. <!-- 读取配置文件 -->
  13. <property name="configLocation" value="classpath:/properties/quartz.properties"/>
  14. <property name="autoStartup" value="true"/>
  15. </bean>

配置quartz.properties:

下载了quartz.jar后,在\quartz-2.2.1\src\org\quartz\目录下有个quartz.properties的文件,可以根据自己的需要更改其中的配置内容。

  1. #批处理常量表 QUARTZ2.2.1
  2. #============================================================================
  3. # Configure Main Scheduler Properties
  4. #============================================================================
  5. org.quartz.scheduler.instanceName = MyQuartzScheduler
  6. org.quartz.scheduler.instanceId = AUTO
  7. #============================================================================
  8. # Configure ThreadPool
  9. #============================================================================
  10. org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
  11. org.quartz.threadPool.threadCount = 10
  12. org.quartz.threadPool.threadPriority = 5
  13. org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread:true
  14. #============================================================================
  15. # Configure JobStore
  16. #============================================================================
  17. org.quartz.jobStore.misfireThreshold = 10000
  18. org.quartz.jobStore.class = org.springframework.scheduling.quartz.LocalDataSourceJobStore
  19. org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate
  20. org.quartz.jobStore.isClustered = true --是否集群部署
  21. #任务表前缀
  22. org.quartz.jobStore.tablePrefix = test_qrtz_

创建任务表:

jar包文件中,给出了所有数据库的建表语句。可以根据给出的sql语句创建表。

【spring配置】——spring整合Quartz定时器

调度类:

  1. package com.xy.utils.scheduler;
  2. import org.quartz.JobBuilder;
  3. import org.quartz.JobDetail;
  4. import org.quartz.Scheduler;
  5. import org.quartz.SimpleScheduleBuilder;
  6. import org.quartz.Trigger;
  7. import org.quartz.TriggerBuilder;
  8. import com.xy.utils.SpringUtils.SpringUtilsFromClassPathXml;
  9. public class quartzTest {
  10. //从Spring中获取调度bean工厂
  11. public static Scheduler scheduler = (Scheduler)SpringUtilsFromClassPathXml.getBean("schedulerBeanFactory");
  12. public static void main(String args[]) throws Exception {
  13. JobDetail jobDetail= JobBuilder.newJob(TestJob.class)
  14. .withIdentity("job","group")
  15. .build();
  16. Trigger trigger= TriggerBuilder.newTrigger().withIdentity("job","group").startNow().withSchedule(
  17. SimpleScheduleBuilder.simpleSchedule()
  18. .withIntervalInSeconds(10) //时间间隔
  19. .repeatForever()
  20. )
  21. .build();
  22. scheduler.scheduleJob(jobDetail, trigger);
  23. scheduler.start();
  24. }
  25. }

任务类(需要实现job接口):

  1. package com.xy.utils.scheduler;
  2. import org.quartz.Job;
  3. import org.quartz.JobExecutionContext;
  4. import org.quartz.JobExecutionException;
  5. public class TestJob implements Job {
  6. public void execute(JobExecutionContext arg0) throws JobExecutionException {
  7. System.out.println("*****执行批处理任务******");
  8. }
  9. }

此时执行该类就会将任务数据写入数据库中。

【spring配置】——spring整合Quartz定时器

调度任务工具类:

自定义任务调度工具类:

  1. package com.xy.utils.scheduler;
  2. import java.text.ParseException;
  3. import java.text.SimpleDateFormat;
  4. import java.util.Date;
  5. import org.quartz.CronScheduleBuilder;
  6. import org.quartz.CronTrigger;
  7. import org.quartz.DateBuilder;
  8. import org.quartz.Job;
  9. import org.quartz.JobBuilder;
  10. import org.quartz.JobDetail;
  11. import org.quartz.Scheduler;
  12. import org.quartz.SchedulerException;
  13. import org.quartz.SimpleScheduleBuilder;
  14. import org.quartz.Trigger;
  15. import org.quartz.TriggerBuilder;
  16. import org.quartz.TriggerKey;
  17. import org.quartz.DateBuilder.IntervalUnit;
  18. import org.slf4j.Logger;
  19. import org.slf4j.LoggerFactory;
  20. import com.xy.common.SysContent;
  21. public class SchedulerJobUtils {
  22. private static Logger logger = LoggerFactory.getLogger(SchedulerJobUtils.class);
  23. public static Scheduler scheduler = (Scheduler)SysContent.applicationContext.getBean("schedulerBeanFactory");
  24. //public static Scheduler scheduler = (Scheduler)SpringUtilsFromClassPathXml.getBean("schedulerBeanFactory");
  25. public static String dateFormate = "ss mm HH dd MM ? yyyy";
  26. public static SimpleDateFormat cronSdf = new SimpleDateFormat(dateFormate);
  27. public static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
  28. /**
  29. * 数据库放入一个指定时间的任务,任务只执行一次
  30. * @see 适合对数据进行定时删除,修改等等
  31. * @param <T>
  32. * @param clazz  要执行任务类class,任务类必须继承Job类
  33. * @param jobName 任务名称
  34. * @param groupName 分组名称
  35. * @param executeTime 执行时间,格式:yyyy-MM-dd HH:mm:ss
  36. * @return
  37. */
  38. public static<T> boolean putSpecifyTimeSchedulerJobToDB(Class<? extends Job> clazz,String jobName,String groupName,String executeTime){
  39. //定义一个job
  40. JobDetail job = JobBuilder.newJob(clazz).withIdentity(jobName, groupName).build();
  41. //定义一个TriggerKey
  42. TriggerKey triggerKey = TriggerKey.triggerKey(jobName, groupName);
  43. SchedulerJob schedulerJob = new SchedulerJob();
  44. schedulerJob.setJobName(jobName);
  45. schedulerJob.setGroupName(groupName);
  46. job.getJobDataMap().put("schedulerJob", schedulerJob);
  47. Date executeDate = null;
  48. try {
  49. executeDate = sdf.parse(executeTime);
  50. } catch (ParseException e) {
  51. logger.info("method putSchedulerJobToDB execute error!exception={}",e);
  52. }
  53. String dbExecuteTime = cronSdf.format(executeDate);
  54. CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity(triggerKey).withSchedule(CronScheduleBuilder.cronSchedule(dbExecuteTime)).build();
  55. try {
  56. scheduler.scheduleJob(job, cronTrigger);
  57. } catch (SchedulerException e) {
  58. logger.info("method putSchedulerJobToDB execute error!exception={}",e);
  59. }
  60. return true;
  61. }
  62. /**
  63. * 数据库放入一条指定开始时间,指定间隔时间,指定次数的任务
  64. * @param <T>
  65. * @param clazz 任务类
  66. * @param jobName  任务名
  67. * @param groupName 分组名
  68. * @param seconds   间隔时间,以秒为单位
  69. * @param count 执行次数,0为一直执行
  70. * @param startSecondsToNow 开始时间(距离现在?秒)
  71. * @return
  72. * @throws SchedulerException
  73. */
  74. @SuppressWarnings("unchecked")
  75. public static<T> boolean putPeriodSchedulerJobToDB(Class<? extends Job> clazz,String jobName,String groupName,
  76. int seconds,int count,int startSecondsToNow){
  77. JobDetail jobDetail= JobBuilder.newJob(clazz).withIdentity(jobName,groupName).build();
  78. TriggerBuilder triggerBuilder = TriggerBuilder.newTrigger().withIdentity(jobName,groupName);
  79. if(startSecondsToNow==0){
  80. triggerBuilder.startNow();
  81. }else{
  82. triggerBuilder.startAt(DateBuilder.futureDate(startSecondsToNow,IntervalUnit.SECOND));
  83. }
  84. SimpleScheduleBuilder scheduleBuilder = SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(seconds);
  85. if(count==0){
  86. scheduleBuilder.repeatForever();
  87. }else{
  88. scheduleBuilder.withRepeatCount(count);
  89. }
  90. Trigger trigger = triggerBuilder.withSchedule(scheduleBuilder).build();
  91. try {
  92. scheduler.scheduleJob(jobDetail,trigger);
  93. } catch (SchedulerException e) {
  94. logger.info("put putPeriodSchedulerJobToDB error,error={}",e);
  95. }
  96. return true;
  97. }
  98. }

任务类:

  1. package com.xy.utils.scheduler;
  2. import org.joda.time.DateTime;
  3. import org.quartz.Job;
  4. import org.quartz.JobExecutionContext;
  5. import org.quartz.JobExecutionException;
  6. import org.slf4j.Logger;
  7. import org.slf4j.LoggerFactory;
  8. public class TestSchedulerTask implements Job{
  9. private static Logger logger = LoggerFactory.getLogger(TestSchedulerTask.class);
  10. public void execute(JobExecutionContext context) throws JobExecutionException {
  11. logger.info("**********TestSchedulerTask1 start at={}",new DateTime().toString("yyyy-MM-dd HH:mm:ss"));
  12. logger.info("**********I'm Ok!************");
  13. logger.info("**********TestSchedulerTask1 end at={}",new DateTime().toString("yyyy-MM-dd HH:mm:ss"));
  14. }
  15. /**
  16. * 调度任务工具类测试
  17. * 10秒执行一次,无限次数,30秒后开始
  18. * @param args
  19. */
  20. public static void main(String[] args) {
  21. System.out.println(SchedulerJobUtils.putPeriodSchedulerJobToDB(TestSchedulerTask.class, "myJob", "myGroup", 10, 0, 30));
  22. }
  23. }

数据库里的任务表:

【spring配置】——spring整合Quartz定时器

打印出的日志:
2016-01-10 00:37:34,810  INFO TestSchedulerTask1:14 - **********TestSchedulerTask1 start at=2016-01-10 00:37:34
2016-01-10 00:37:34,810  INFO TestSchedulerTask1:15 - **********I'm Ok!************
2016-01-10 00:37:34,811  INFO TestSchedulerTask1:16 - **********TestSchedulerTask1 end at=2016-01-10 00:37:34

2016-01-10 00:37:44,690  INFO TestSchedulerTask1:14 - **********TestSchedulerTask1 start at=2016-01-10 00:37:44
2016-01-10 00:37:44,691  INFO TestSchedulerTask1:15 - **********I'm Ok!************
2016-01-10 00:37:44,691  INFO TestSchedulerTask1:16 - **********TestSchedulerTask1 end at=2016-01-10 00:37:44

2016-01-10 00:37:54,697  INFO TestSchedulerTask1:14 - **********TestSchedulerTask1 start at=2016-01-10 00:37:54
2016-01-10 00:37:54,697  INFO TestSchedulerTask1:15 - **********I'm Ok!************
2016-01-10 00:37:54,697  INFO TestSchedulerTask1:16 - **********TestSchedulerTask1 end at=2016-01-10 00:37:54

上一篇:在 iOS 应用中直接跳转到 AppStore 的方法--备用


下一篇:Spring配置方式