我试图在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的无限洋葱抽象层让我很难解决这个简单的问题。关于事物初始化顺序的所有重要细节都是隐藏的。答案 0 :(得分:1)
我不确定为什么你需要在WebApplicationInitializer
中执行此操作。如果要配置为您执行运行状况检查的@Bean
,请在ApplicationListener<ContextRefreshedEvent>
中执行此操作。您可以从那里(事件的来源)访问ConfigurableApplicationContext
并关闭它。这将关闭Spring上下文。如果您希望Servlet和Web应用程序死掉,则抛出异常。
除非您启动它,否则无法杀死容器(Tomcat等)。您可以尝试使用嵌入式容器(例如Spring Boot将为您轻松完成此操作)。
答案 1 :(得分:1)
据我了解,您无需明确调用close()
。
只是让异常转义afterPropertiesSet()
,Spring应该自动停止实例化剩余的bean并关闭整个上下文。
如果你必须对已经初始化的bean进行一些清理,你可以使用@PreDestroy
。