JAVA WEB服务监听与周期执行某一任务

[size=x-large][b]说明:[/b]本人为菜鸟,此文主要用于记录个人学习笔记,也希望给予同时菜鸟的朋友一点帮助,文中解决方法有些采用了他人文章,感谢原创者的付出。由于其他原因,本人只给出本人查阅采用的文章链接,对于参考文章非该作者原创的情况,希望原创者能够理解。
[b]应用背景:[/b]在做一个java web工程服务器为tomcat,里面有个功能大致要求如下,周期性的检查计算机目录下的某个文件是否更新,若更新则对该文件进行分析。
[b]关键词:[/b]ServletContextListener;Timer;TimerTask
[b]解决方法:[/b]
搜索资料后,发现采用ServletContextListener接口能够监听ServletContext对象的生命周期,实际上就是监听Web应用的生命周期。当Servlet容器启动或终止Web应用时,会触发ServletContextEvent事件,该事件由ServletContextListener 来处理。这样我们可以根据这个特性实现在web应用程序初始化时,自动运行一些初始化程序。在 ServletContextListener 接口中定义了处理ServletContextEvent事件的两个方法。该接口中有两个主要方法:contextDestroyed()与contextInitialized(),前者由Servlet容器调用在web应用的“初始化”阶段,后者的调用在web应用的“结束”阶段。在部署ServletContextListene的时候,需要在web.xml中对相关参数进行配置,相关更详细地信息,可以自行搜索。现就本文具体代码进行分析。
首先是web.xml
[/size]

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<display-name></display-name>
<listener>
<listener-class>Analyze</listener-class>
</listener>
<context-param>
<description>Analyze的监听周期以秒为单位</description>
<param-name>period</param-name>
<param-value>5</param-value>
</context-param>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>

[size=x-large]<listener-class>用于设定执行监听的类,后面的<param-name>和<param-value>用来设定后续schedule()方法中所需的周期。[/size]

Analyze.java

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

public class Analyze implements ServletContextListener {

private static java.util.Timer timer = null;

public void contextDestroyed(ServletContextEvent event) {
timer.cancel();
event.getServletContext().log("定时器已销毁,任务执行结束");
}

public void contextInitialized(ServletContextEvent event) {
timer = new java.util.Timer(true);
javax.servlet.ServletContext ctx = event.getServletContext();
ctx.log("定时器已启动,任务开始执行");

//读取web.xml配置文件中的参数值
long period = Long.valueOf((String) ctx.getInitParameter("period"))
.longValue() * 1000;
timer.schedule(new NewTask(event.getServletContext()), 0, period);
//schedule方法中三个参数各自意义:所需要执行的任务;延迟时间(0表示起动Web容器(或服务器)时就立即执行此任务);任务的执行间隔时间[单位:毫秒]
}
}

[size=x-large]Analyze类实现了ServletContextListener接口,实现了其中的两个方法,对于contextInitialized方法,主要说明的是,通过该方法,调用Timer类执行其schedule()方法,并读取web.xml中<context-param>
信息,作为参数放在Timer.schedule()方法中,并执行任务。对于Timer.schedule()方法需要说明一下:
schedule()方法根据参数的不同,带来的效果也不一样,主要说明如下:
schedule(TimerTask task, long delay)文档说明:Schedules the specified task for execution after the specified delay。大意是在延时delay毫秒后执行task,且只执行一次
schedule(TimerTask task, long delay, long period)的注释:Schedules the specified task for repeated fixed-delay execution, beginning after the specified delay。大意是在延时delay毫秒后重复的执行task,周期是period毫秒。本文采用的是后者。
监听启动后,调用Timer类,利用schedule调用NewTask类,该类继承TimerTask类。[/size]
NewTask.java

import java.util.List;
import java.util.TimerTask;
import javax.servlet.ServletContext;
import wstate.State;

public class NewTask extends TimerTask {
public NewTask(ServletContext servletContext) {
this.servletContext = servletContext;
}

private ServletContext servletContext = null;
private static boolean isRunning = false; // 运行标志(表示是否正在运行计划的任务)

@Override
public void run() {
if (!isRunning) { // 当未执行此任务时则开始执行
List<State> l = NodesAnalysis.GetStates();
if (l.size() != 0) {
servletContext.setAttribute("states", l);
}
isRunning = false; // 将任务执行标志设置为执行完毕
} else {
System.out.println("任务正在运行中");
}
}
}

[size=x-large]对于Timer和TimerTask的介绍,个人觉得http://hi.baidu.com/wmqxyh/item/a386395ba03db50ce6c4a5a9所写非常详细,贴出来,感谢该作者:
Timer与TimerTask都在java.util包中,它们是与任务调度相关的类。Timer是一个定时器,可以设置成在特定时间或按特定时间周期产生信号;TimerTask负责定义所要执行的任务。将Timer和TimerTask关联起来,在Timer发出信号的时候执行TimerTask定义的任务。 TimerTask是一个抽象类,只要继承TimerTask类并实现run()方法就行了。run()方法体就是定义所要执行的任务的地方,在Timer发出信号的时候,这个run()方法就会执行。要想知道本次run()方法再何时被启动,可以使用TimerTask类中的方法long scheduledExecutionTime(),使用这个方法不会造成时间精度的误差,它比System.currentTimeMillis()更节省资源。 可以通过Timer类的schedule(...)方法来设定发出信号的特定时间或特定时间周期,并与一个TimerTask类的实例相关联。使用void scheduleAtFixedRate(...)方法可以产生固定周期信号。可以使用Timer类的cancle()方法停止Timer,不再发出信号,此时,Timer与TimerTask也就脱离关系了。也可以通过TimerTask类中的cancle()方法达到同样的目的。 有一个问题,如果run()方法里面的任务在下一次信号出现之前还没有完成怎么办?有下面两种情况:(1)在用schedule(...)方法调度时:如果run()方法里面的任务在信号周期之内完成,那么下一次的信号就会在预定的时间产生;如果run()方法里面的任务在下一次信号出现之前还没有完成,那么下一次的信号就会延迟,并且上一个run()执行完成之后就立即产生下一个信号,下一个run()立即开始执行。(2)在用scheduleAtFixedRate(...)方法调度时:如果run()方法里面的任务在信号周期之内完成,那么下一次的信号就会在预定的时间产生;如果run()方法里面的任务在下一次信号出现之前还没有完成,那么等到run()执行完成之后,下一次的信号产生就尽量赶上本应该产生信号的时间,意思就是如果有累计的(从第一次信号算起)超时存在,那么下一次的信号就会在run()方法执行完之后立即产生;如果没有累计的超时存在,那么就按照周期产生信号。 另外,根据规范,如果调用cancle()时run()仍在执行,那么run()会继续执行直到完成。
感谢以下作者的辛勤劳动。
http://www.cnblogs.com/soarwell/archive/2009/03/18/1415206.html
http://www.cnblogs.com/secret1998/archive/2010/05/26/1744432.html
http://blog.csdn.net/blueling51/article/details/6931026
http://hi.baidu.com/wmqxyh/item/a386395ba03db50ce6c4a5a9
[/size]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值