Timer定时器

断了今生、忘了曾经 提交于 2019-12-03 17:00:20

 

Timer定时器+mybatis

建立3个类:TimerManager类(定时器的启动和定时执行);XXXTimerTask类(定时任务类,即定时执行的服务);XXXTimeTaskListener类(定时器的监听器)。

1.TimerManager类

该类主要负责定时器的启动和执行。其中,PERIOD_DAY属性为定时任务的执行时间间隔(毫秒数)。我这里定的是2个小时。具体的方法中,先定义定时器第一次执行任务的时间,即下图中的date,然后new一个Timer(定时器)和TimerTask(定时任务),最后利用定时器的schedule方法,将定时任务、第一次执行时间和任务执行时间间隔传入定时器中。

其中要注意的一点,当项目启动时,启动时间若早于当日定时器第一次执行时间(下图中的date),定时任务不会立刻执行。

 1  2 
 3 import java.util.Calendar;
 4 import java.util.Date;
 5 import java.util.Timer;
 6 
 7 /*
 8 * Service :需要定时器重复执行的服务
 9 */
10 public class TimerManager {
11     //时间间隔
12     private static final long PERIOD_DAY = 2 * 60 * 60 * 1000;
13     
14     public TimerManager(Service service) {    
15          Calendar calendar = Calendar.getInstance(); 
16                 
17          /*** 定制第一次执行定时任务的时间 ***/
18          calendar.set(Calendar.HOUR_OF_DAY, 8);
19          calendar.set(Calendar.MINUTE, 10);
20          calendar.set(Calendar.SECOND, 0);
21           
22          Date date=calendar.getTime(); //第一次执行定时任务的时间
23          //System.out.println("before 方法比较:"+date.before(new Date()));
24          //如果第一次执行定时任务的时间 小于 当前的时间
25          //此时要在 第一次执行定时任务的时间 加一天,以便此任务在下个时间点执行。如果不加一天,任务会立即执行。循环执行的周期则以当前时间为准
26 /*         if (date.before(new Date())) {
27              date = this.addDay(date, 1);
28              System.out.println(date);
29          }
30 */          
31          Timer timer = new Timer();
32          XXXTimerTask task = new XXXTimerTask(service);
33          //安排指定的任务在指定的时间开始进行重复的固定延迟执行。
34          timer.schedule(task,date,PERIOD_DAY);
35         }
36 
37         // 增加或减少天数
38 /*        public Date addDay(Date date, int num) {
39          Calendar startDT = Calendar.getInstance();
40          startDT.setTime(date);
41          startDT.add(Calendar.DAY_OF_MONTH, num);
42          return startDT.getTime();
43         }*/
44 }

 

 

2.XXXTimerTask类

该类即定时任务类,该类需要继承java中的TimerTask类。为了能让定时器融合springmybatis框架,我将此任务类看成一个对象。

具体代码如下:

其中run方法是由TimeTask继承而来,里面主要是定时器需要执行的具体服务。service是我在这个定时任务里需要调用的服务,是可以通过注解注入的。

 1 import java.util.TimerTask;
 2 
 3 import org.springframework.beans.factory.annotation.Autowired;
 4 import org.springframework.context.annotation.Configuration;
 5 
 6 
 7 
 8 @Configuration
 9 public class XXXTimerTask extends TimerTask {
10     
11     @Autowired
12     private Service service;
13     
14     public XXXTimerTask() {
15     }
16     
17     public XXXTimerTask(Service service) {
18         super();
19         this.service = service;
20     }
21     
22     @Override
23     public void run() {
24         
25         try {
26             //在这里写你要执行的内容
27             service.xxx();
28         } catch (Exception e) {
29             e.printStackTrace();
30             System.out.println("-------------解析信息发生异常--------------");
31         }
32     }
33 }
34     

 

3.XXXTimeTaskListener类

该类为定时器的监听器,需要继承ServletContextListener类。其中contextInitialized()方法和contextDestroyed()均是继承而来。contextInitialized()Context()的初始化方法,contextDestroyed()是销毁方法。

 

 1 package cn.dsmc.rivs.cmm.interceptor;
 2 
 3 import javax.servlet.ServletContextEvent;
 4 import javax.servlet.ServletContextListener;
 5 
 6 import org.springframework.web.context.WebApplicationContext;
 7 import org.springframework.web.context.support.WebApplicationContextUtils;
 8 
 9 
10 public class XXXTimeTaskListener implements  ServletContextListener {
11     //Context()初始化方法
12     @Override
13     public void contextInitialized(ServletContextEvent sce) {
14         //获得Spring容器
15         WebApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(sce.getServletContext());
16         //从Spring容器中获得VisitatorialPlanService的实例
17         Service service = ctx.getBean(Service.class);
18         //新建一个定时管理器
19         new TimerManager(service);
20     }
21     
22     public XXXTimeTaskListener() {
23         super();
24     }
25     
26     @Override
27     public void contextDestroyed(ServletContextEvent sce) {
28         // 销毁
29         
30     }
31 }

 

 

4.在web.xml中的配置

最后要在web.xml中进行配置。其中一定要注意的一点,监听器的配置一定一定要放在spring本身的监听器的后面。

1     <!--XXXTimeTaskListener 监听器-->
2     <listener>
3         <listener-class>cn...XXXTimeTaskListener</listener-class>
4     </listener>

 

个人总结:

在启动web项目时,Servlet容器(比如Tomcat)会读web.xml配置文件中的两个节点和,节点用来加载appliactionContext.xml(Spring的配置文件),节点用来创建监听器(比如TestTaskListener)实例。Listener的生命周期是由servlet容器管理的,例中的TestTaskListener是由servlet容器实例化并调用其contextInitialized方法的,但是,service是通过@Service注解的,也就是说service是由Spring容器管理的,在Spring容器外无法直接通过依赖注入得到Spring容器管理的bean实例的引用。为了在Spring容器外得到Spring容器管理的bean,可以使用Spring提供的工具类WebApplicationContextUtils。也就是说,可以在servlet容器管理的Listener中使用该工具类获Spring管理的bean

 

简单点,就是定时器在spring容器的外面,因此和spring的注解是有冲突的。而我们使用了mybatis框架,不可避免会使用注解注入(service层调用dao层)。所以我们需要将调用的service手动注入到spring容器中(XXXTimeTaskListener类中的contextInitialized()初始化方法)。

 

需要注意的地方:

7.1 虽然我的这个项目架构中没有appliactionContext.xml文件,但手动注入即WebApplicationContextUtils.getWebApplicationContext(sce.getServletContext());方法还是可以正常使用的。

7.2 不要忘记XXXTimeTask中的无参构造,否则启动时会报XXXTimeTask bean无法创建的异常。

7.3 我是在XXXTimeTaskListener类(监听器)中,将XXXTimeTask需调用的Service实例化。

 

 

 

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!