Tomcat servlet 应用程序的后台线程 [重复]
Posted
技术标签:
【中文标题】Tomcat servlet 应用程序的后台线程 [重复]【英文标题】:Background Thread for a Tomcat servlet app [duplicate] 【发布时间】:2010-10-21 23:25:36 【问题描述】:我对 Tomcat 不是很熟悉,在我看来,它基本上被抽象为一个 cgi 服务器,可以在调用之间保存 JVM ——不过我知道它可以做的远不止这些。
我正在寻找一种在 Tomcat 服务器启动时启动 background 线程的方法,该线程会定期更新服务器上下文(在我的特定情况下,这是一个监听来自其他人的心跳的线程服务和更新可用性信息,但可以想象它的多种用途)。
有没有标准的方法来做到这一点?上下文的启动和更新/查询?
任何指向相关文档和/或代码示例的指针将不胜感激。
【问题讨论】:
值得注意的是,如果有比初始化上下文更方便的地方,通常可以在需要时启动线程。例如。它可能在特定 servlet 的 init 方法中,或者在特定类首次初始化时等。 【参考方案1】:如果您使用基于 spring 的框架,您可以在 beans.xml 中指定要初始化的类/线程。所以当tomcat启动时,beans.xml会初始化里面提到的所有类。如果需要,您还可以传递构造函数参数。以下是相同的示例。
beans.xml
<bean id="monitoringSvc" class="com.mypackage.MonitoringService">
<constructor-arg value="60"></constructor-arg>
</bean>
MonitoringService.java
public class MonitoringService
private MyThread myThread;
public MonitoringService(int seconds)
myThread = new MyThread(seconds);
myThread.start();
【讨论】:
【参考方案2】:如果你想在你的 WAR 部署时启动一个线程,你可以在 web.xml 中定义一个上下文监听器:
<web-app>
<listener>
<listener-class>com.mypackage.MyServletContextListener</listener-class>
</listener>
</web-app>
然后像这样实现那个类:
public class MyServletContextListener implements ServletContextListener
private MyThreadClass myThread = null;
public void contextInitialized(ServletContextEvent sce)
if ((myThread == null) || (!myThread.isAlive()))
myThread = new MyThreadClass();
myThread.start();
public void contextDestroyed(ServletContextEvent sce)
try
myThread.doShutdown();
myThread.interrupt();
catch (Exception ex)
【讨论】:
啊!谢谢,这很简单。我是否正确地说“ServletContext”是我需要修改以使该线程将信息传递给我的 servlet,以便它可以使用我的心跳侦听器收集的状态? 是的,我的回答中错过了这一部分。 :) ServletConext 可从 ServletContextEvent 获得,它可以传递到您的 Thread 对象中,该对象可以获取/设置所有线程可用的属性。 那个时候,怎么可能访问MyServletContextListener
来查询线程呢?【参考方案3】:
将<load-on-startup>1</load-on-startup>
放入web.xml 中的<servlet>
块将强制您的servlet 的init()
在Tomcat 启动后立即发生,而不是等待第一个请求到达。如果您想从 init()
生成后台线程,这很有用。
【讨论】:
这对我来说成功了,与这里的其他解决方案相比非常简单,但非常适合启动一些后台应用程序或守护程序。谢谢!【参考方案4】:我只是对 Chris 给出的非常详细的回答做一些小改动;我会将myThread
设置为myThread.setDaemon(true);
的守护线程,只要您有其他需要您的后台线程的非守护线程在工作,这基本上会保持线程处于活动状态。当所有这些线程完成时,您的守护程序线程将被 JVM 停止,您无需在contextDestroyed
中自行处理它。
但这只是我的 2 美分。
【讨论】:
除非你仍然需要在 contextDestroyed 中处理它。守护进程在最后一个非守护线程终止时终止,而不是在 servlet 上下文终止时终止。如果部署 WAR 文件来替换当前正在运行的文件,则旧 servlet 上下文中的守护线程将继续运行。这反过来又保留了该上下文的 ClassLoader,这是一个 PermGen 内存泄漏,这很糟糕。【参考方案5】:我正在寻找一种在 Tomcat 服务器启动时启动后台线程的方法
我认为您正在寻找一种在 您的 Web 应用程序由 Tomcat 启动时启动后台线程的方法。
这可以使用ServletContextListener 来完成。它在 web.xml 中注册,将在您的应用程序启动或停止时调用。然后,您可以使用普通的 Java 方法创建(或稍后停止)您的线程,以创建线程(或 ExecutionService)。
【讨论】:
以上是关于Tomcat servlet 应用程序的后台线程 [重复]的主要内容,如果未能解决你的问题,请参考以下文章
Servlet“已启动一个线程但未能停止它”-Tomcat 中的内存泄漏
Day694.Tomcat如何支持异步Servlet -深入拆解 Tomcat & Jetty