Spring的两种定时器

1. spring学习系列 -- 定时器一TimerTask

spring定时器一般有两种

TimerTask、Quartz。本节只讲TimerTask

需要的包

aopalliance-1.0.jar

commons-logging-1.1.1.jar

spring-aop-3.0.6.RELEASE.jar

spring-asm-3.0.6.RELEASE.jar

spring-beans-3.0.6.RELEASE.jar

spring-context-3.0.6.RELEASE.jar

spring-core-3.0.6.RELEASE.jar

spring-expression-3.0.6.RELEASE.jar

 

TimerTask实例:同时启动2个定时器,执行任务

定时执行任务的类继承TimerTask:

Java代码

 收藏代码

  1. public class EmailReportTask extends TimerTask{     
  2.     @Override     
  3.     public void run() {     
  4.         System.out.println(" EmailReportTask Run... ");  
  5.     }       
  6. }   
  7.   
  8. public class PageReportTask extends TimerTask{     
  9.     @Override     
  10.     public void run() {     
  11.         System.out.println("PageReportTask Run...");  
  12.     }       
  13. }     

 

spring的配置文件:

Xml代码

 收藏代码

  1.        
  2.   
  3.   
  4.   
  5.    
  6.     class="org.springframework.scheduling.timer.ScheduledTimerTask">     
  7.          
  8.          
  9.          
  10.    
  11.     class="org.springframework.scheduling.timer.ScheduledTimerTask">     
  12.          
  13.           
  14.    
  15.   
  16.       
  17.          
  18.          
  19.           
  20.               
  21.               
  22.             
  23.          
  24.    

 

测试代码:

Java代码

 收藏代码

  1. public class TestBaseService {  
  2.     protected ApplicationContext ctx = new ClassPathXmlApplicationContext(  
  3.             new String[]{  
  4.                     "classpath:resource/spring.xml"  
  5.             }  
  6.     );  
  7.   
  8.     @Test  
  9.     public void timer(){  
  10.         try{  
  11.             // 这个是主线程,如果结束了,则定时器也会结束,所有设置时间要长  
  12.             Thread.sleep(36 * 1000);  
  13.         }catch(Exception e){  
  14.             e.printStackTrace();  
  15.         }  
  16.    
  17.     }  
  18. }  

参考文献:

  • spring 定时器如何配置  
  • Spring中Quartz的配置  
  • spring定时任务之quartz  
  • Spring定时器的两种实现方式  

2.Spring的第二种定时器quartz

在上一节的基础上,讨论Spring的第二种定时器quartz


Spring的两种定时器_第1张图片

  重点包: 

quartz-1.8.6.jar

org.springframework.context.support-3.1.1.RELEASE.jar

 

  包说明

        quartz包请使用1.8.6或以下的版本,因为quartz2.0版本和spring3.1.1存在冲突,会抛出

 

目的

   通过quartz定时循环执行一个任务

 

任务类

    该类还包含一个属性sTest及其set/get方法

 

Java代码

 收藏代码

  1. public class MyJob extends QuartzJobBean {  
  2.     private String sTest;  
  3.   
  4.     @Override  
  5.     protected void executeInternal(JobExecutionContext job)  
  6.             throws JobExecutionException {  
  7.         // TODO Auto-generated method stub  
  8.         System.out.println("sTest = " + sTest);  
  9.         System.out.println("MyJob Run...");  
  10.     }  
  11.   
  12.     public String getsTest() {  
  13.         return sTest;  
  14.     }  
  15.   
  16.     public void setsTest(String sTest) {  
  17.         this.sTest = sTest;  
  18.     }  
  19.       
  20. }  

 

spring的配置文件

    JobDetailBean:设置要执行任务的类,在这里通过jobDataAsMap属性还可以设置任务类的属性。

  Trigger用于设置人物类启动的时间,循环的间隔等工作信息。spring包含2种Trigger :

simpleReportTrigger功能类似上一篇文章的TimerTask,设置任务延迟多久启动,循环间隔等信息

cronReportTrigger可以设置任务精确工作的时间

  SchedulerFactoryBean:仅仅有以上2个类设置是不够的,如果要启动定时器,还需要通过此类设置要启动的trigger。

Xml代码

 收藏代码

  1.   
  2.          
  3.          
  4.         com.hry.spring.timertask.MyJob     
  5.          
  6.          
  7.              
  8.                 
  9.                 10   
  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.      

 

 

 

通过上篇文章的测试代码执行以上程序,则有如下输入,说明我们程序成功了。

 

 

Html代码

 收藏代码

  1. sTest = 10  
  2. MyJob Run...  
  3. sTest = 10  
  4. MyJob Run...  
  5. sTest = 10  
  6. MyJob Run...  
  7. sTest = 10  
  8. MyJob Run...  
  9. sTest = 10  
  10. MyJob Run...  

  

 

CronTriggerBean的精华是cron表达式,以下是关于cron表达式(来自网络)

Cron 表达式依照顺序有7 个字段:

 

小时

月内日期

周内日期

年(可选字段)

特殊字符

 

Cron 触发器利用一系列特殊字符,如下所示:

 

反斜线(/)字符表示增量值。例如,在秒字段中“5/15”代表从第 5 秒开始,每 15 秒一次。

 

问号(?)字符和字母 L 字符只有在月内日期和周内日期字段中可用。问号表示这个字段不包含具体值。所以,如果指定月内日期,可以在周内日期字段中插入“?”,表示周内日期值无关紧要。字母 L 字符是 last 的缩写。放在月内日期字段中,表示安排在当月最后一天执行。在周内日期字段中,如果“L”单独存在,就等于“7”,否则代表当月内周内日期的最后一个实例。所以“0L”表示安排在当月的最后一个星期日执行。

 

在月内日期字段中的字母(W)字符把执行安排在最靠近指定值的工作日。把“1W”放在月内日期字段中,表示把执行安排在当月的第一个工作日内。

 

井号(#)字符为给定月份指定具体的工作日实例。把“MON#2”放在周内日期字段中,表示把任务安排在当月的第二个星期一。

 

星号(*)字符是通配字符,表示该字段可以接受任何可能的值。

字段 允许值 允许的特殊字符 

秒 0-59 , - * / 

分 0-59 , - * / 

小时 0-23 , - * / 

日期 1-31 , - * ? / L W C 

月份 1-12 或者 JAN-DEC , - * / 

星期 1-7 或者 SUN-SAT , - * ? / L C # 

年(可选) 留空, 1970-2099 , - * /

表达式意义 

"0 0 12 * * ?" 每天中午12点触发 

"0 15 10 ? * *" 每天上午10:15触发 

"0 15 10 * * ?" 每天上午10:15触发 

"0 15 10 * * ? *" 每天上午10:15触发 

"0 15 10 * * ? 2005" 2005年的每天上午10:15触发 

"0 * 14 * * ?" 在每天下午2点到下午2:59期间的每1分钟触发 

"0 0/5 14 * * ?" 在每天下午2点到下午2:55期间的每5分钟触发 

"0 0/5 14,18 * * ?" 在每天下午2点到2:55期间和下午6点到6:55期间的每5分钟触发 

"0 0-5 14 * * ?" 在每天下午2点到下午2:05期间的每1分钟触发 

"0 10,44 14 ? 3 WED" 每年三月的星期三的下午2:10和2:44触发 

"0 15 10 ? * MON-FRI" 周一至周五的上午10:15触发 

"0 15 10 15 * ?" 每月15日上午10:15触发 

"0 15 10 L * ?" 每月最后一日的上午10:15触发 

"0 15 10 ? * 6L" 每月的最后一个星期五上午10:15触发 

"0 15 10 ? * 6L 2002-2005" 2002年至2005年的每月的最后一个星期五上午10:15触发 

"0 15 10 ? * 6#3" 每月的第三个星期五上午10:15触发 

每天早上6点

0 6 * * *

 

每两个小时

0 */2 * * * 

 

晚上11点到早上8点之间每两个小时,早上八点

0 23-7/2,8 * * *

 

每个月的4号和每个礼拜的礼拜一到礼拜三的早上11点

0 11 4 * 1-3 

 

1月1日早上4点

0 4 1 1 *

 

3.Spring的两种定时器的区别

前2节绍了spring的两种定时器:TimerTask 和 Quartz,本节要在这两节的基础上,讲讲两者的区别。

 

精确度和功能

   Quartz可以通过cron表达式精确到特定时间执行,而TimerTask不能。Quartz拥有TimerTask所有的功能,而TimerTask则没有。

 

任务类的数量

    TimerTask和Quartz每次执行任务时,每次调用的是不是都是同一个任务类对象,还是每次都不一样?现在做如下实验,每次执行任务时,将任务类对象本身打印出来。

 

Quartz任务类

 

Java代码

 收藏代码

  1. public class MyJob extends QuartzJobBean {  
  2.     private String sTest;  
  3.   
  4.     @Override  
  5.     protected void executeInternal(JobExecutionContext job)  
  6.             throws JobExecutionException {  
  7.         // TODO Auto-generated method stub  
  8.         System.out.println("sTest = " + sTest);  
  9.         System.out.println("MyJob Run..." + this);  
  10.     }  
  11.   
  12.     // set/get 略  
  13.       
  14. }  

Quartz输出结果

 

Java代码

 收藏代码

  1. sTest = 10  
  2. MyJob Run...com.hry.spring.timertask.MyJob@1060478  
  3. sTest = 10  
  4. MyJob Run...com.hry.spring.timertask.MyJob@db4fa2  
  5. sTest = 10  
  6. MyJob Run...com.hry.spring.timertask.MyJob@491c4c  

 

从输出结果可以看出,Quartz每次执行都创建一个新的任务类对象。

 

 

TimerTask任务类

 

Java代码

 收藏代码

  1. public class EmailReportTask extends TimerTask{     
  2.     // 每次执行过程中num的值都会发生变化,说明此事使用的是同一个类对象  
  3.     private int num = 0;  
  4.     @Override     
  5.     public void run() {     
  6.         System.out.println("num = " + num++);  
  7.         System.out.println(this);  
  8.     }       
  9. }    

 

TimerTask任务类的输出结果

 

Java代码

 收藏代码

  1. num = 0  
  2. com.hry.spring.timertask.EmailReportTask@1581593  
  3. PageReportTask Run...  
  4. num = 1  
  5. com.hry.spring.timertask.EmailReportTask@1581593  
  6. PageReportTask Run...  

 从输出结果可以看出,TimerTask每次执行时,都是使用同一个对象

 从以上的分析,可以得出结论:Quartz每次执行任务都创建一个新的任务类对象,而TimerTask则每次使用同一个任务类对象。

 

对异常的处理

一个循环执行的任务,如果某一次执行任务时,因为某些原因抛出异常,则定时器是否还会在下一个执行任务的时间点执行任务吗?下面通过模拟在任务类中抛出异常,来模拟这种情况,并测试两种定时器如何处理这种情况。

Quartz任务类

 

Java代码

 收藏代码

  1. public class MyJob extends QuartzJobBean {  
  2.     private String sTest;  
  3.   
  4.     @Override  
  5.     protected void executeInternal(JobExecutionContext job)  
  6.             throws JobExecutionException {  
  7.         // TODO Auto-generated method stub  
  8.         System.out.println("sTest = " + sTest);  
  9.         System.out.println("MyJob Run..." + this);  
  10.         throw new RuntimeException("Test");  
  11.     }  
  12.   
  13.     // set/get 方法略  
  14.       
  15. }  

 

 

Quartz输出结果

 

Html代码

 收藏代码

  1. sTest = 10  
  2. MyJob Run...com.hry.spring.timertask.MyJob@16f25a7  
  3. 2013-01-05 19:58:37,381 [org.springframework.scheduling.quartz.SchedulerFactoryBean#0_Worker-3] ERROR [org.quartz.core.JobRunShell] - Job DEFAULT.reportJob threw an unhandled Exception:   
  4.   java.lang.RuntimeException: Test  
  5.     at com.hry.spring.timertask.MyJob.executeInternal(MyJob.java:24)  
  6.     at org.springframework.scheduling.quartz.QuartzJobBean.execute(QuartzJobBean.java:113)  
  7.     at org.quartz.core.JobRunShell.run(JobRunShell.java:223)  
  8.     at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:549)  
  9. 2013-01-05 19:58:37,396 [org.springframework.scheduling.quartz.SchedulerFactoryBean#0_Worker-3] ERROR [org.quartz.core.ErrorLogger] - Job (DEFAULT.reportJob threw an exception.  
  10.   org.quartz.SchedulerException: Job threw an unhandled exception. [See nested exception: java.lang.RuntimeException: Test]  
  11.     at org.quartz.core.JobRunShell.run(JobRunShell.java:234)  
  12.     at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:549)  
  13. Caused by: java.lang.RuntimeException: Test  
  14.     at com.hry.spring.timertask.MyJob.executeInternal(MyJob.java:24)  
  15.     at org.springframework.scheduling.quartz.QuartzJobBean.execute(QuartzJobBean.java:113)  
  16.     at org.quartz.core.JobRunShell.run(JobRunShell.java:223)  
  17.     ... 1 more  
  18. sTest = 10  
  19. MyJob Run...com.hry.spring.timertask.MyJob@110c31  
  20. 2013-01-05 19:58:39,381 [org.springframework.scheduling.quartz.SchedulerFactoryBean#0_Worker-4] ERROR [org.quartz.core.JobRunShell] - Job DEFAULT.reportJob threw an unhandled Exception:   
  21.   java.lang.RuntimeException: Test  
  22.     at com.hry.spring.timertask.MyJob.executeInternal(MyJob.java:24)  
  23.     at org.springframework.scheduling.quartz.QuartzJobBean.execute(QuartzJobBean.java:113)  
  24.     at org.quartz.core.JobRunShell.run(JobRunShell.java:223)  
  25.     at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:549)  
  26. 2013-01-05 19:58:39,396 [org.springframework.scheduling.quartz.SchedulerFactoryBean#0_Worker-4] ERROR [org.quartz.core.ErrorLogger] - Job (DEFAULT.reportJob threw an exception.  
  27.   org.quartz.SchedulerException: Job threw an unhandled exception. [See nested exception: java.lang.RuntimeException: Test]  
  28.     at org.quartz.core.JobRunShell.run(JobRunShell.java:234)  
  29.     at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:549)  
  30. Caused by: java.lang.RuntimeException: Test  
  31.     at com.hry.spring.timertask.MyJob.executeInternal(MyJob.java:24)  
  32.     at org.springframework.scheduling.quartz.QuartzJobBean.execute(QuartzJobBean.java:113)  
  33.     at org.quartz.core.JobRunShell.run(JobRunShell.java:223)  
  34.     ... 1 more  

  以上结果中多次出现

 

Java代码

 收藏代码

  1. sTest = 10    
  2. MyJob Run...com.hry.spring.timertask.MyJob@110c31   

可以看出,尽管每次执行任务时,任务类都会抛出异常,但是Quartz定时器,依然在下一个任务执行时间点执行任务,并没有因为异常,而导致定时器关闭,不再执行循环任务。

 

TimerTask任务类

 

Java代码

 收藏代码

  1. public class EmailReportTask extends TimerTask{     
  2.     // 每次执行过程中num的值都会发生变化,说明此事使用的是同一个类对象  
  3.     private int num = 0;  
  4.     @Override     
  5.     public void run() {     
  6.         System.out.println("num = " + num++);  
  7.         throw new RuntimeException("test");  
  8.     }       
  9. }     

 

TimerTask输出结果

 

Java代码

 收藏代码

  1. num = 0  
  2. Exception in thread "org.springframework.scheduling.timer.TimerFactoryBean#0" java.lang.RuntimeException: test  
  3.     at com.hry.spring.timertask.EmailReportTask.run(EmailReportTask.java:11)  
  4.     at java.util.TimerThread.mainLoop(Unknown Source)  
  5.     at java.util.TimerThread.run(Unknown Source)  

 TimerTask抛出异常后,后续再也没有执行此任务了,并且定时器所在的线程也自动结束。

 

通过以上的分析,可以知道Quartz的某次执行任务过程中抛出异常,不影响下一次任务的执行,当下一次执行时间到来时,定时器会再次执行任务;而TimerTask则不同,一旦某个任务在执行过程中抛出异常,则整个定时器生命周期就结束,以后永远不会再执行定时器任务。

你可能感兴趣的:(JAVA)