`
hcx_2008
  • 浏览: 118007 次
  • 性别: Icon_minigender_1
  • 来自: 西安
社区版块
存档分类
最新评论

J2EE应用:定时器

    博客分类:
  • J2EE
阅读更多
定时器(引用)

好多朋友用过Windows的任务计划,也有不少程序迷自己曾写过时钟报警、系统自动关机等趣味程序,可却很少有朋友在Web工程中实现过类似功能。今天有空把笔者先前曾在Tomcat上实现的类似功能,搬出来与大家共享。

    早在几年前,我公司跟某市财政局合作项目开发,为加强财政局对所属单位财务状况的有效监管,开发、实施了财政局数据中心项目。此项目采用B/S加C/S混合结构模式。财政局Web服务器上架设数据同步接收装置,由市属单位每天下班前把财务信息通过HTTP协议上传至财政局中心服务器,与Web服务器上的接收装置对接。财政局内部各部门需要查阅大量财务信息,获取完备的市属单位当前财务状况信息,各部门按职能划分,需要准确的获取各部门各自所关注的汇总信息,以财政报表的形式提供。

    因财政数据量大,实时计算财政报表速度较慢,当初就考虑用报表缓存来减轻服务器的负担,但用缓存需要一个合理的缓存更新机制。考虑到各市属单位每天下班前才把财务数据上传,财政局每天所查看到的财务信息其实并不包括当天(除非有某位领导等到所属单位全部上传完之后才来查看信息,应该已经下班了),所以要是能实现任务计划调度,在每晚深夜把当天及历史财务信息汇总,更新缓存,速度瓶颈不就解决了吗。

    当时由于系统核心是基于Web部署的,报表计算引擎也相应的部署在Tomcat容器上,因此如果想要借用Windows的任务计划来实现定时计算,就需要额外编写普通桌面应用程序接口,稍显复杂。于是就琢磨着想在Web上实现,经过查阅较多相关资料,发现Java定时器(java.util.Timer)有定时触发计划任务的功能,通过配置定时器的间隔时间,在某一间隔时间段之后会自动有规律的调用预先所安排的计划任务(java.util.TimerTask)。另外,由于我们希望当Web工程启动时,定时器能自动开始计时,在整个Web工程的生命期里,定时器能在每晚深夜触发一次报表计算引擎。因此定时器的存放位置也值得考查,不能简单的存在于单个Servlet或JavaBean中,必须能让定时器宿主的存活期为整个Web工程生命期,在工程启动时能自动加载运行。结合这两点,跟Servlet上下文有关的侦听器就最合适不过了,通过在工程的配置文件中加以合理配置,会在工程启动时自动运行,并在整个工程生命期中处于监听状态。

    下面就Servlet侦听器结合Java定时器来讲述整个实现过程。要运用Servlet侦听器需要实现javax.servlet.ServletContextListener接口,同时实现它的contextInitialized(ServletContextEvent event)和contextDestroyed(ServletContextEvent event)两个接口函数。考虑定时器有个建立和销毁的过程,看了前面两个接口函数,就不容置疑的把建立的过程置入contextInitialized,把销毁的过程置入contextDestroyed了。

    我把ServletContextListener的实现类取名为ContextListener,在其内添加一个定时器,示例代码如下所示(为考虑篇幅,仅提供部分代码供读者参考):


    private java.util.Timer timer = null;
    public void contextInitialized(ServletContextEvent event) {
        timer = new java.util.Timer(true);
        event.getServletContext().log("定时器已启动");        
         timer.schedule(new MyTask(event.getServletContext()), 0, 60*60*1000);
        event.getServletContext().log("已经添加任务调度表");
    }
    public void contextDestroyed(ServletContextEvent event) {
        timer.cancel();
        event.getServletContext().log("定时器销毁");
    }

    以上代码中, timer.schedule(new MyTask(event.getServletContext()), 0, 60*60*1000)这一行为定时器调度语句,其中MyTask是自定义需要被调度的执行任务(在我的财政数据中心项目中就是报表计算引擎入口),从java.util.TimerTask继承,下面会重点讲述,第三个参数表示每小时(即60*60*1000毫秒)被触发一次,中间参数0表示无延迟。其它代码相当简单,不再详细说明。

   下面介绍MyTask的实现,上面的代码中看到了在构造MyTask时,传入了javax.servlet.ServletContext类型参数,是为记录Servlet日志方便而传入,因此需要重载MyTask的构造函数(其父类java.util.TimerTask原构造函数是没有参数的)。在timer.schedule()的调度中,设置了每小时调度一次,因此如果想实现调度任务每24小时被执行一次,还需要判断一下时钟点,以常量C_SCHEDULE_HOUR表示(晚上12点,也即0点)。同时为防止24小时执行下来,任务还未执行完(当然,一般任务是没有这么长的),避免第二次又被调度以引起执行冲突,设置了当前是否正在执行的状态标志isRunning。示例代码如下所示:


    private static final int C_SCHEDULE_HOUR   = 0;
    private static boolean isRunning = false;
         private ServletContext context = null;
    public MyTask(ServletContext context) {
        this.context = context;
    }
    public void run() {
        Calendar cal = Calendar.getInstance();        
        if (!isRunning)  {           
            if (C_SCHEDULE_HOUR == cal.get(Calendar.HOUR_OF_DAY)) {            
                    isRunning = true;                
                context.log("开始执行指定任务");
                
                //TODO 添加自定义的详细任务,以下只是示例
                int i = 0;
                while (i++ < 10) {
                    context.log("已完成任务的" + i + "/" + 10);
                }

                isRunning = false;
                context.log("指定任务执行结束");               
            }            
        } else {
            context.log("上一次任务执行还未结束");
        }
    }

    上面代码中“//TODO……”之下四行是真正被调度执行的演示代码(在我的财政数据中心项目中就是报表计算过程),您可以换成自己希望执行的语句。

     到这儿,ServletContextListener和MyTask的代码都已完整了。最后一步就是把ServletContextListener部署到您的Web工程中去,在您工程的web.xml配置文件中加入如下三行:
   
        com.test.ContextListener
    
    当然,上面的com.test得换成您自己的包名了。保存web.xml文件后,把工程打包部署到Tomcat中即可。任务会在每晚12点至凌晨1点之间被执行,上面的代码会在Tomcat的日志文件中记录如下:

2003-12-05 0:21:39 开始执行指定任务
2003-12-05 0:21:39 已完成任务的1/10
    ……
2003-12-05 0:21:39 已完成任务的10/10
2003-12-05 0:21:39 指定任务执行结束
***********************************************************************************************************************
关于定时任务,似乎跟时间操作的联系并不是很大,但是前面既然提到了定时任务,索性在这里一起解决了。

设置定时任务很简单,用Timer类就搞定了。



一、延时执行



首先,我们定义一个类,给它取个名字叫TimeTask,我们的定时任务,就在这个类的main函数里执行。代码如下:

package test;

import java.util.Timer;

public class TimeTask {



public static void main(String[] args){

Timer timer = new Timer();

timer.schedule(new Task(), 60 * 1000);

}

}



解释一下上面的代码。

上面的代码实现了这样一个功能,当TimeTask程序启动以后,过一分钟后执行某项任务。很简单吧:先new一个Timer对象,然后调用它的schedule方法,这个方法有四个重载的方法,这里我们用其中一个,

public void schedule(TimerTask task,long delay)



首先,第一个参数



第一个参数就是我们要执行的任务。

这是一个TimerTask对象,确切点说是一个实现TimerTask的类的对象,因为TimerTask是个抽象类。上面的代码里面,Task就是我们自己定义的实现了TimerTask的类,因为是在同一个包里面,所以没有显性的import进来。Task类的代码如下



package test;

import java.util.TimerTask;

public class Task extends TimerTask {

public void run(){

System.out.println("定时任务执行");

}

}

我们的Task必须实现TimerTask的方法run,要执行的任务就在这个run方法里面,这里,我们只让它往控制台打一行字。



第二个参数



第二个参数是一个long型的值。这是延迟的时间,就是从程序开始以后,再过多少时间来执行定时任务。这个long型的值是毫秒数,所以前面我们的程序里面,过一分钟后执行用的参数值就是 60 * 1000。



二、循环执行



设置定时任务的时候,往往我们需要重复的执行这样任务,每隔一段时间执行一次,而上面的方法是只执行一次的,这样就用到了schedule方法的是另一个重载函数

public void schedule(TimerTask task,long delay,long period)



前两个参数就不用说什么了,最后一个参数就是间隔的时间,又是个long型的毫秒数(看来java里涉及到时间的,跟这个long是脱不了干系了),比如我们希望上面的任务从第一次执行后,每个一分钟执行一次,第三个参数值赋60 * 1000就ok了。



三、指定执行时间



既然号称是定时任务,我们肯定希望由我们来指定任务指定的时间,显然上面的方法就不中用了,因为我们不知道程序什么时间开始运行,就没办法确定需要延时多少。没关系,schedule四个重载的方法还没用完呢。用下面这个就OK了:

public void schedule(TimerTask task,Date time)

比如,我们希望定时任务2006年7月2日0时0分执行,只要给第二个参数传一个时间设置为2006年7月2日0时0分的Date对象就可以了。

有一种情况是,可能我们的程序启动的时候,已经是2006年7月3日了,这样的话,程序一启动,定时任务就开始执行了。



schedule最后一个重载的方法是

public void schedule(TimerTask task,Date firstTime,long period)



没必要说什么了吧:)



四、j2ee中的定时任务

在实际的项目中,往往定时任务需要对web工程中的资源进行操作,这样一来,用上面的单个程序的方式可能就有点力不从心了,因为很多web工程的资源它操作不到。

解决的办法是,使用Servlet,把执行定时任务的那些代码放到Servlet的init()函数里就可以了
分享到:
评论
2 楼 hhujsj 2010-05-29  
顶 对我做的项目很有帮组!!!
1 楼 iRoger 2009-07-14  
不错,写的很仔细,为什么没人顶呢

相关推荐

    spring 定时器

    Quartz 是一个开源的作业调度框架,它完全由 Java 写成,并设计用于 J2SE 和 J2EE 应用中。它提供了巨大的灵活性而不牺牲简单性。你能够用它来为执行一个作业而创建简单的或复杂的调度。本系统结合通过 Spring 来...

    J2EE spring mvc mybatis bootstrap HTML5 后台框架 控制台 mysql版本_spring3.0

    微信接口(身份验证,文本、图文回复等) 微信远程控制服务器重启、锁定、其它应用程序 15.java Quartz 定时器 (定时执行某程序,精确到秒,可设置周期) 16.java websocket 即时通讯技术,点对点,群聊,单聊,EXT4...

    Java定时器 quartz jar包

    Quartz是OpenSymphony开源组织在Job scheduling领域又一个开源项目,它可以与J2EE与J2SE应用程序相结合也可以单独使用。Quartz可以用来创建简单或为运行十个,百个,甚至是好几万个Jobs这样复杂的程序。Jobs可以做成...

    JBPM3.1Help(中文)

    第一章:介绍 JBoss jBPM 是一个复杂的可扩展的工作流管理系统. JBoss jBPM 有直观的流程...当然它也可以用在吞吐量极为关键的J2EE 群应用服务器环境中. JBoss jBPM 可以同任何数据库配置可以部署在任何应用服务器上.

    工作流chm手册jbpm3.1

    JBoss jBPM 是一个复杂的可扩展的工作流管理系统. JBoss jBPM 有直观的流程语言来表示商业...当然它也可以用在吞吐量极为关键的J2EE 群应用服务器环境中. JBoss jBPM 可以同任何数据库配置可以部署在任何应用服务器上

    jBPM中文用户指南 chm格式

    JBoss jBPM 是一个复杂的可扩展的工作流管理系统. JBoss jBPM 有直观的流程语言来表示...当然它也可以用在吞吐量极为关键的J2EE 群应用服务器环境中. JBoss jBPM 可以同任何数据库配置可以部署在任何应用服务器上.

    jBoss jBMP.chm

    JBoss jBPM 是一个复杂的可扩展的工作流管理系统. JBoss jBPM 有直观的流程语言来...当然它也可以用在吞吐量极为关键的J2EE 群应用服务器环境中. JBoss jBPM 可以同任何数据库配置可以部署在任何应用服务器上.

    JBPM用户手册

    JBOSS jBPM是一个灵活的、可扩展的工作流管理系统。...另外,也可以通过把它部署在J2EE集群应用服务器中,用在吞吐量极为关键的环境中。 JBOSS jBPM可被配置为任何数据库,并且可以部署到任何应用服务器

    工作流详解

    JBoss jBPM 是一个复杂的可扩展的工作流管理系统. JBoss jBPM 有直观的流程...当然它也可以用在吞吐量极为关键的J2EE 群应用服务器环境中. &lt;br&gt;JBoss jBPM 可以同任何数据库配置可以部署在任何应用服务器上.

    J2EE spring mvc mybatis bootstrap HTML5 后台框架 控制台 oracle版本_spring3.0

    微信接口(身份验证,文本、图文回复等) 微信远程控制服务器重启、锁定、其它应用程序 15.java Quartz 定时器 (定时执行某程序,精确到秒,可设置周期) 16.java websocket 即时通讯技术,点对点,群聊,单聊,EXT4...

    jbpm教程

    JBoss jBPM 是一个复杂的可扩展的工作流管理系统. JBoss jBPM 有直观的...当然它也可以用在吞吐量极为关键的J2EE 群应用服务器环境中. &lt;br&gt;JBoss jBPM 可以同任何数据库配置可以部署在任何应用服务器上. &lt;br&gt;

    jbpm中文用户指南

    JBoss jBPM 是一个复杂的可扩展的工作流管理系统. JBoss jBPM 有直观的...当然它也可以用在吞吐量极为关键的J2EE 群应用服务器环境中. &lt;br&gt;JBoss jBPM 可以同任何数据库配置可以部署在任何应用服务器上. &lt;br&gt;

    工作流督-办管理

    该系统采用J2EE技术开发 ,jdk1.6 数据库:mysql 开发工具myeclipse6.5 服务器:tomcat6.0 系统:vista 整和:struts+hibernate+spring+jbpm 本系统业务流程用工作流(jbpm),数据库持久化采用 hibernate,视图层采用...

    quartz-all-1.6.1.jar

    Quartz是一个开源的作业调度框架,它完全由Java写成,并设计用于J2SE和J2EE应用中。它提供了巨大的灵 活性而不牺牲简单性。你能够用它来为执行一个作业而创建简单的或复杂的调度。它有很多特征,如:数据库支持,...

    Quartz-2.2.3-distribution

    Quartz是OpenSymphony开源组织在Job scheduling领域又一个开源项目,它可以与J2EE与J2SE应用程序相结合也可以单独使用。Quartz可以用来创建简单或为运行十个,百个,甚至是好几万个Jobs这样复杂的程序。Jobs可以做成...

    JAVA上百实例源码以及开源项目源代码

    像坐标控制、旋转矩阵、定时器、生成图像、数据初始化、矩阵乘法、坐标旋转、判断是否是顺时针方向排列、鼠标按下、放开时的动作等,都可在本源码中得以体现。 Java编写的显示器显示模式检测程序 2个目标文件 内容...

    JAVA上百实例源码以及开源项目

    像坐标控制、旋转矩阵、定时器、生成图像、数据初始化、矩阵乘法、坐标旋转、判断是否是顺时针方向排列、鼠标按下、放开时的动作等,都可在本源码中得以体现。 Java编写的显示器显示模式检测程序 2个目标文件 内容...

Global site tag (gtag.js) - Google Analytics