`
hcx_2008
  • 浏览: 122133 次
  • 性别: 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  
不错,写的很仔细,为什么没人顶呢

相关推荐

    Quartz/J2EE (定时服务)

    Quartz是一款开源的作业调度框架,它在Java社区中被广泛应用,特别是在J2EE环境中,用于实现定时任务的管理。Quartz提供了强大的功能,能够帮助开发者精确地安排和执行任务,比如定期备份数据库、发送邮件或者执行...

    j2ee的应用-swing组件介绍

    本篇文章将深入探讨Swing组件的基本知识,以及如何利用它们在J2EE开发中创建简单游戏和应用程序。 首先,Swing组件库包含了各种控件,如按钮(JButton)、文本框(JTextField)、标签(JLabel)、面板(JPanel)、...

    J2EE-API-7和J2EE-API-6中英文对照版

    **J2EE (Java 2 Platform, Enterprise Edition)** 是Java平台的一个版本,专注于服务器端的软件开发,尤其适合构建和部署分布式企业级应用程序。J2EE API是它的一部分,提供了丰富的接口和类库,用于开发各种功能,...

    j2ee原理

    J2EE容器,如应用服务器,提供了运行和管理EJB、Servlet、JSP等组件的环境,并提供了诸如连接池、定时器服务、工作调度等功能。 13. **部署描述符** 部署描述符(如web.xml、ejb-jar.xml)定义了应用的配置信息,...

    quartz 定时器

    - **集成方式**:Quartz可以在应用中启动或运行,也可以作为一个独立的应用(带有RMI接口),或在一个J2EE应用服务器中运行,并作为其他J2EE组件的一种引用资源。 7. **与Java定时器的区别**: - **持久化**:...

    J2EE_API_6

    这个压缩文件包含了开发者在使用J2EE 6进行企业级应用开发时所需要的重要参考资料。尽管当前J2EE已经演进到Java EE 8,但J2EE 6对于那些不追求最新技术或对稳定性和兼容性有较高需求的项目来说,仍然是一个可靠的...

    Quartz定时器从入门到进阶

    Quartz定时器是一个开源的作业调度框架,专为J2SE和J2EE应用程序设计,完全用Java编写。它的核心优势在于提供强大的灵活性和简单性,使得开发者可以轻松创建简单的或复杂的任务调度。Quartz支持多种特性,如数据库...

    J2EE6 API 学习文档

    J2EE(Java Platform, Enterprise Edition)是Java平台上用于构建企业级应用的框架。J2EE6版本,发布于2009年,是Java EE平台的一个重要里程碑,它引入了一系列新特性和改进,旨在提高开发效率、简化部署和管理,...

    j2ee面试题及答案全

    【J2EE面试题及答案全】涉及到的IT知识点主要集中在HTML、CSS、JavaScript和Web基础知识上,这些都是构建和交互Web应用的基础。下面是对这些知识点的详细解释: 1. **HTML**:全称为HyperText Markup Language,是...

    j2ee6-javaEE6文档 手册 CHM

    此外,还支持定时器服务和Asynchronous方法调用,提高了性能和灵活性。 4. **Java Persistence API(JPA)2.0**:JPA是ORM(对象关系映射)的标准,2.0版本增强了对多对多关联的支持,添加了查询语言JPA QL,以及...

    总结J2EE中使用任务调度三种方式

    在J2EE应用程序中,任务调度是一个常见的需求,例如定期执行数据备份、发送邮件或执行维护任务等。本文将深入探讨三种在J2EE环境中实现任务调度的方式:Java内置的定时器API(java.util.Timer)、Servlet容器的定时...

    基于J2EE的Ajax宝典

    - **解决多余刷新的问题**:通过定时器定期检查新消息。 - **解析服务器响应**:将服务器返回的数据解析为可展示的形式。 - **何时发送请求**:根据用户行为决定何时发起请求。 - **特点**:无需重新加载页面即可...

    J2EE_6_API英文版

    EJB 3.1在J2EE 6中显著降低了使用门槛,通过注解简化了组件的声明,引入了轻量级会话bean和无状态会话bean,以及定时器服务。 5. **Java Persistence API (JPA)**:JPA提供了一种统一的方式来管理关系数据库中的...

    J2EE api_6

    Java 2 Platform, Enterprise Edition (J2EE) 是一个为企业级应用开发提供全面框架的平台。API 6,即Java EE 6,是这个平台的一个重要版本,它在2009年发布,带来了许多重要的改进和新特性,旨在简化开发过程,提高...

    spring 定时器

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

    J2EE的基础知识

    Java 2 Platform, Enterprise Edition(J2EE)是Oracle公司推出的用于构建企业级分布式应用程序的框架,它提供了服务器端的编程模型和运行环境。在移动游戏开发领域,尤其是在早期,J2ME(Java Micro Edition)是...

    2021-2022计算机二级等级考试试题及答案No.5542.docx

    10. J2EE request 对象方法:在 J2EE 中,`getParameterValues(String name)` 可以获取表单组件对应多个值的请求数据数组。 11. Excel 应用领域:Excel 主要用于统计分析、财务管理分析和经济管理等领域。 12. ...

Global site tag (gtag.js) - Google Analytics