Java 在web应用程序中注册shutDownHook

Java 在web应用程序中注册shutDownHook,java,spring,tomcat,web,ioc-container,Java,Spring,Tomcat,Web,Ioc Container,我们如何在web应用程序中注册下拉钩子 在web.xml或applicationContext.xml中注册它有什么方法吗 我知道,如果我们将应用程序与主类一起使用,它很简单 ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml"); context.registerShutdownHook(); 但是web应用程序呢?由于它在web应用程序

我们如何在web应用程序中注册下拉钩子

在web.xml或applicationContext.xml中注册它有什么方法吗

我知道,如果我们将应用程序与主类一起使用,它很简单

ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");
    context.registerShutdownHook();

但是web应用程序呢?由于它在web应用程序中使用ContextListener,您可以使用在部署和取消部署应用程序时触发的:

public class MyServletContextListener implements ServletContextListener {
    public void contextInitialized(ServletContextEvent sce) {
        //application is being deployed
    }
    public void contextDestroyed(ServletContextEvent sce) {
        //application is being undeployed
    }
}
您可以通过检索当前Spring上下文来访问Spring bean:

public void contextDestroyed(ServletContextEvent sce) {
    ServletContext ctx = sce.getServletContext();
    WebApplicationContext springContext = WebApplicationContextUtils.getWebApplicationContext(ctx);
    //retrieve your Spring beans here...
    SomeSpringBean bean = (SomeSpringBean)ctx.getBean("someSprinbgBean");
    //...
}

独立(非web)应用程序中的RegisterShotDownhook():

package com.myapp;

import javax.servlet.ServletContextEvent;
import com.myapp.resources.requiring.clean.shutdown
import org.springframework.web.context.ContextCleanupListener;

public class MyWebApplicationCleanupListener extends ContextCleanupListener {

    @Override
    public void contextDestroyed(ServletContextEvent event) {
        // put your shutdown code in here

        MyResourceNeedingShutdown dataStore = MyResourceNeedingShutdown.getInstance();
        dataStore.shutdown();
    }

}
@PreDestroy
注释用于bean方法,以便在从上下文中删除bean或上下文关闭时收到通知

当调用
context.close()
context.registerShutdownHook()
时,将触发关闭事件

@Component(value="someBean")
public class SomeBean {

    @PreDestroy
    public void destroy() {
        System.out.println("Im inside destroy...");
    }
}
我希望你已经知道了



web应用程序中的RegisterShotDownhook():

package com.myapp;

import javax.servlet.ServletContextEvent;
import com.myapp.resources.requiring.clean.shutdown
import org.springframework.web.context.ContextCleanupListener;

public class MyWebApplicationCleanupListener extends ContextCleanupListener {

    @Override
    public void contextDestroyed(ServletContextEvent event) {
        // put your shutdown code in here

        MyResourceNeedingShutdown dataStore = MyResourceNeedingShutdown.getInstance();
        dataStore.shutdown();
    }

}
在web应用程序中,DispatcherServlet/ContextListener创建ApplicationContext,并在服务器关闭时关闭上下文。不需要显式调用
context.close()
context.registerShutdownHook()


当服务器关闭时,bean上的
@PreDestory
方法将被自动通知。

使用Spring 3+可以向应用程序上下文添加ContextCleanupListener

这样在启动时注册侦听器(您可能更喜欢使用xml配置,但同样适用)

运行关闭代码的ContextCleanupListener的实现:

package com.myapp;

import javax.servlet.ServletContextEvent;
import com.myapp.resources.requiring.clean.shutdown
import org.springframework.web.context.ContextCleanupListener;

public class MyWebApplicationCleanupListener extends ContextCleanupListener {

    @Override
    public void contextDestroyed(ServletContextEvent event) {
        // put your shutdown code in here

        MyResourceNeedingShutdown dataStore = MyResourceNeedingShutdown.getInstance();
        dataStore.shutdown();
    }

}

例如,当您运行(比如说tomcat)并按CTRL+C将其关闭时,如果在调试器中放置断点,您将立即看到contextDestroyed方法被命中

@Luiggi Mendoza在我在web.xml中添加条目时,答案开始工作

<web-app ...>
   <listener>
    <listener-class>
             com....MyServletContextListener
        </listener-class>
   </listener>
</web-app>
但重要的是首先由Spring调用@PreDestroy,然后在contextdestroy调用之后,再由非Spring线程调用@PreDestroy

所以如果你想完成一些工作;此时,如果您想确保其他资源线程可用,请保留此@PreDestroy

@PreDestroy
public void cleanup() {
    eventTaskExecutor.shutdown();
    try {
        /**
         * This is blocking call to avoid other threads (like logger demon thread)
         * not closed before this completes the job. Else worker thread cannot log
         * event.
         * 
         * This will be the case when thread is busy in getting the web response,
         * better will wait for that, and log the web response.
         * 
         */
        eventTaskExecutor.awaitTermination(20, TimeUnit.SECONDS);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }   
}
只需知道下面是在类中获取@postConstruct钩子的另一种方法

@Autowired
public void setApplicationContext(ApplicationContext applicationContext) {
    applicationContext.getBean("myRelatedClass", MyRelatedClass.class);
}

还有一件事是@PreDestroy只对单例对象调用,而对原型对象不可用。

谢谢您的回答。你们能告诉我,我怎样才能得到代表SPRING上下文的对象吗。我可以在其上调用context.registerShutdownHook()@Javakid如果您了解bean作为原型会发生什么,我不需要给出解释:流程将根据从上下文中删除的实例进行调用。人们不使用
prototype
(正确与否),主要是因为bean的默认范围是
singleton
。由于OP没有提供流程的行为方式或任何场景,因此这可能是最好的选择。可能清理过程需要几个bean和它们的编排。@Javakid在维护遗留应用程序,特别是非常旧的应用程序时,没有关注点分离定律(只需看看应用程序具有的单片体系结构),因此这是可用的选项。在这里,我唯一确信的是,如果您希望在普通web应用程序中的某个特定位置启动任何清理过程,那么这是最安全的方法。我的回答中没有涉及特定于框架的好处(或者说是你自己毁灭的后门),对于这种情况,最好了解
@PreDestruct
。请注意,
@PreDestruct
不是来自Spring,而是来自JavaEE。谢谢您的建议。但这种方法不起作用。我添加了必要的函数@Override public void contextInitialized(ServletContextSce){ServletContext=sce.getServletContext();WebApplicationContext springContext=WebApplicationContextILS.getWebApplicationContext(context);ClassPathXmlApplicationContext applicationContext=(ClassPathXmlApplicationContext)springContext.getParent();applicationContext.RegisterShotdownhook();}但是当我调用applicationContext.RegisterShotdownhook()时1.我有空指针excaption@KanagaveluSugumarSpring会为您连接所有东西。如果某些东西无法连接是因为延迟连接或无法创建bean,您必须检查为什么没有创建。响应非常好。@PreDestroy是关键!非常感谢:-)@Kalyan::@PreDestroy被要求销毁bean,这意味着,如果bean不是单例的,那么每当容器删除bean时,就会多次调用它。@Anandj.Kadhi这不是真的-您有什么解决方案吗?