References:《Tomcat 启动时加载WEB应用中的后台程序》[1],《配置Tomcat Listener》[2]
要做的事情很简单,就是在Tomcat启动WEB服务器的时候同时启动一个后台程序,做一些事情。
[1]里面介绍的方法是通过不响应Request的Servlet来实现,通过设置<load-on-startup>标签和Servlet里面的static代码段来实现。
[2]介绍了另一个方法,通过实现ServletContextListener,并在web.xml文件里配置listener来实现后台程序的启动。
于是我打算先用第二种方法做一个demo:实现的功能:用户在页面输入值,action把这个值甩到一个消息队列里面,然后后台这个线程不断的从这个队列里面读值,输出到控制台
MyListener.java version1
package Listeners;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import Support.MessageQManager;
import Support.MessageQueue;
public class MyListener implements ServletContextListener {@Overridepublic void contextInitialized(ServletContextEvent sce) {System.err.println("DBConnListener Startup!");
DemoThread dt = new DemoThread(MessageQManager.mq);
Thread th1 = new Thread(dt);
th1.start();System.err.println("DemoThread Startup!");
}@Overridepublic void contextDestroyed(ServletContextEvent sce) {}}
DemoThread.java ---version1
package BackStage;
import Support.MessageQueue;
public class DemoThread implements Runnable {private MessageQueue mq=null;public DemoThread(MessageQueue mq){
this.mq=mq;
}public void run() {while(true){readFromMsgQueue();}}public Object readFromMsgQueue(){
Object o=mq.recv();System.err.println(o.toString());return o;
}}
MessageQueue.java
package Support;
import java.util.Vector;
public class MessageQueue {private Vector<Object> queue = null;public MessageQueue() {
queue = new Vector<Object>();
}public synchronized void send(Object o) {queue.addElement(o);}public synchronized Object recv() {if (queue.size() == 0)
return null;Object o = queue.firstElement();queue.removeElementAt(0);// or queue[0] = null can also work
return o;
}}
MessageQManager.java
package Support;
public class MessageQManager {public static MessageQueue mq=new MessageQueue();}
前端代码就不贴出来了,就是把输入的值send到消息队列里面。
web.xml配置片段:<listener>标签要在filter-mapping标签下面
<listener><listener-class>Listeners.MyListener</listener-class></listener>
然后满心欢喜的用eclipse启动服务器呢!O(∩_∩)O~
结果呢~出错了!!(⊙_⊙)
NoClassDefFoundError! 搜了一把,很多是因为找不到ServletContextListener,但是我的是能找到的,只是找不到自定义的类而已。研究了一段时间发现跟tomcat加载class的时间跟顺序有关系,貌似挺复杂的……没研究明白。
不管了先跑起来再说,于是果断把DemoThread甩到MyListener里面当一个内部类
MyListener.java version2
package Listeners;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import Support.MessageQManager;
import Support.MessageQueue;
public class MyListener implements ServletContextListener {@Overridepublic void contextInitialized(ServletContextEvent sce) {System.err.println("DBConnListener Startup!");
DemoThread dt = new DemoThread(MessageQManager.mq);
Thread th1 = new Thread(dt);
th1.start();System.err.println("DemoThread Startup!");
}@Overridepublic void contextDestroyed(ServletContextEvent sce) {}public class DemoThread implements Runnable {private MessageQueue mq = null;public DemoThread(MessageQueue mq) {
this.mq = mq;
}public void run() {while (true) {readFromMsgQueue();}}public Object readFromMsgQueue() {
Object o = mq.recv();if (o != null)System.err.println(o.toString());return o;
}}}
在运行,成功。
Demo是成功了,可是问题还有:
只能用内部类的方式不是太傻了么……怎样在Tomcat启动的时候加载自定义的类呢?理想状态是通过这一个线程作为入口启动好多个后台程序呢。
-------------------3月30日 更 新--------------------------
今天早上又用第一种方法尝试了一下,没有使用static代码段,而是在init()方法里启动线程,但是依然出现ClassNotFound的错误,直觉告诉我可能是DemoThread写的有问题,于是增加了空的构造函数!居然成功了!!
新的DemoThread.java代码
package BackStage;
import Support.MessageQManager;
import Support.MessageQueue;
public class DemoThread implements Runnable {public DemoThread() {
System.err.println("DemoThread default constructor");
}public void run() {while (true) {readFromMsgQueue(MessageQManager.mq);}}public Object readFromMsgQueue(MessageQueue mq) {
Object o = mq.recv();if (o != null)System.err.println(o.toString());return o;
}}
代码用System.err主要是红色的输出信息比较惹眼哈╮(╯▽╰)╭
MyListener –version3
package Listeners;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import BackStage.DemoThread;
public class MyListener implements ServletContextListener {@Overridepublic void contextInitialized(ServletContextEvent sce) {System.err.println("DBConnListener Startup!");
DemoThread dt = new DemoThread();
Thread th1 = new Thread(dt);
th1.start();System.err.println("DemoThread Startup!");
}@Overridepublic void contextDestroyed(ServletContextEvent sce) {}}