【问题标题】:Handling container stop/reload event处理容器停止/重新加载事件
【发布时间】:2012-02-21 18:55:28
【问题描述】:
一个在 Boot.scala 中启动 ssh 守护程序的 Lift 应用程序。
这是问题所在:当我在 sbt 会话中运行 container:restart / 时,我得到 Address alread in use 异常。
现在有两个问题:
- 在 Boot.scala 中启动依赖服务是否正确?
- 无论如何如何处理 container:stop 事件?
【问题讨论】:
标签:
scala
lift
sbt
xsbt-web-plugin
【解决方案1】:
我不熟悉 Lift,但这个建议应该适用于任何基于 Servlet 的 Web 应用程序。
在web.xml 中注册一个ServletContextListener,并在contextDestroyed 方法中释放所有资源。 (启动应该在contextCreated方法中完成。)
您可以使用setAttribute / getAttribute 来存储和稍后检索服务器。
把这一切放在一起:
import javax.servlet.{ServletContextEvent, ServletContextListener}
final class SshListener extends ServletContextListener{
val attributeKey = "sshServer"
def contextInitialized(sce: ServletContextEvent) {
val server = new Server()
server.start()
sce.getServletContext.setAttribute(attributeKey, server)
}
def contextDestroyed(sce: ServletContextEvent) {
Option(sce.getServletContext.getAttribute(attributeKey)).foreach(_.asInstanceOf[Server].stop())
}
}
class Server {
def start()
def stop()
}
【解决方案2】:
我认为 Lift-y 的做法是使用 LiftRules.unloadHooks。
没有很好的文档记录 (AFAIK),但是如果您查看 Lift 源代码,您会发现当 LiftServlet 为 destroy()ed 时,会执行 LiftRules.unloadHooks 中定义的函数。
您可以使用append 或prepend 方法将函数添加到unloadHooks RulesSeq,具体取决于您希望它们执行的顺序。因此,在您的bootstrap.liftweb.Boot.boot 方法中,您可能会执行类似的操作这个:
sshDaemon.start()
LiftRules.unloadHooks.append( () => sshDaemon.stop() )
(假设这就是您启动和停止 SSH 守护程序的方式。)
我不能 100% 确定在 sbt web-plugin 的 container:restart 命令运行时会调用 LiftServlet.destroy() 方法 - 这是由插件及其与 Jetty 的交互决定的,而不是由 Lift - 而是 container:stop命令绝对可以解决问题。