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~
结果呢~出错了!!(⊙_⊙)
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) {
}
}

