Tomcat 启动后台程序

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 {
	@Override
	public 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!");
	}
	@Override
	public 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~

结果呢~出错了!!(⊙_⊙)

image

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 {
	@Override
	public 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!");
	}
	@Override
	public 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 {
	@Override
	public 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!");
	}
	@Override
	public void contextDestroyed(ServletContextEvent sce) {
		
	}
}
posted on 2011-03-29 15:24  Jersey  阅读(2746)  评论(0编辑  收藏  举报