WebAppInitializer - 如何在启动错误时导致关闭

时间:2014-04-18 19:20:32

标签: spring servlets

我试图在Spring Web应用程序启动时执行一些检查(例如,检查数据库版本是否为例外)。如果检查失败,则应该杀死servlet(或者更好,从未启动),以防止它为任何页面提供服务。理想情况下,包含Tomcat / Netty /任何服务也应该被杀死(尽管这看起来更棘手)。

我无法调用System.exit,因为我的启动检查取决于许多应该安全关闭的服务(例如数据库连接等)。

我找到了this thread,这表明在春天的背景下要求接近。但是,除了报告异常外,spring还会继续启动servlet(见下文)。

我查看了Java Servlet文档 - 它说不要在servlet上调用destroy - 而且我不知道我是否从方法调用Servlet.destroy Servlet对象出现在堆栈的更上方(不想吃掉我自己的尾巴)。事实上,我宁愿首先创建servlet。在开始任何网络服务之前,最好先运行我的启动检查。

这是我拥有的......

@Service
class StartupCheckService extends InitializingBean {

  @Autowired a:OtherServiceToCheckA = null
  @Autowired b:OtherServiceToCheckB = null

  override def afterPropertiesSet = {
    try{

       checkSomeEssentialStuff();   

    } catch {
      case e: Any => {

        // DON'T LET THE SERVICE START!
        ctx = getTheContext();
        ctx.close();

        throw e;
   }
}

关闭调用会导致错误:

BeanFactory not initialized or already closed - call 'refresh' before accessing beans via the ApplicationContext.

大概是因为在bean初始化发生时你不应该调用close(刷新很可能会让我们陷入无限循环)。这是我的启动代码......

class WebAppInitializer extends WebApplicationInitializer {

  def onStartup(servletContext: ServletContext): Unit = {

    val ctx = new AnnotationConfigWebApplicationContext()

    // Includes StartupCheckService
    ctx.register(classOf[MyAppConfig])  
    ctx.registerShutdownHook() // add a shutdown hook for the above context...


    // Can't access StartupCheckService bean here.  


    val loaderListener = new ContextLoaderListener(ctx)
    // Make context listens for servlet events
    servletContext.addListener(loaderListener)

    // Make context know about the servletContext
    ctx.setServletContext(servletContext)

    val servlet: Dynamic = servletContext.addServlet(DISPATCHER_SERVLET_NAME, new DispatcherServlet(ctx))
    servlet.addMapping("/")
    servlet.setLoadOnStartup(1)
}

我已尝试在onStartup中执行此类操作

ctx.refresh()
val ss:StartupService = ctx.getBean(classOf[StartupCheckService])
ss.runStarupRountines()

但显然我不允许在onStartup退出之前调用刷新。

可悲的是,Spring的无限洋葱抽象层让我很难解决这个简单的问题。关于事物初始化顺序的所有重要细节都是隐藏的。

在"之前应该使用Google搜索"纳粹来到...... A B C D E F

2 个答案:

答案 0 :(得分:1)

我不确定为什么你需要在WebApplicationInitializer中执行此操作。如果要配置为您执行运行状况检查的@Bean,请在ApplicationListener<ContextRefreshedEvent>中执行此操作。您可以从那里(事件的来源)访问ConfigurableApplicationContext并关闭它。这将关闭Spring上下文。如果您希望Servlet和Web应用程序死掉,则抛出异常。

除非您启动它,否则无法杀死容器(Tomcat等)。您可以尝试使用嵌入式容器(例如Spring Boot将为您轻松完成此操作)。

答案 1 :(得分:1)

据我了解,您无需明确调用close()。 只是让异常转义afterPropertiesSet(),Spring应该自动停止实例化剩余的bean并关闭整个上下文。

如果你必须对已经初始化的bean进行一些清理,你可以使用@PreDestroy