Зарегистрироваться shutDownHook в веб-приложении

java spring tomcat web ioc-container

24083 просмотра

4 ответа

Как мы можем зарегистрировать ловушку в веб-приложении?

Есть ли способы, чтобы зарегистрировать его в web.xml или applicationContext.xml?

Я знаю, что если мы используем приложение с основным классом, это просто.

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

Но как насчет веб-приложения? Как это использует ContextListener

Автор: slisnychyi Источник Размещён: 12.11.2019 09:51

Ответы (4)


21 плюса

Решение

registerShutdownHook () в автономном (не веб) приложении:

@PreDestroyАннотаций используется по методу боба , чтобы получить уведомление , когда бин удаляется из контекста или когда контекст завершает работу.

Событие выключения запускается, когда context.close()или context.registerShutdownHook()вызывается.

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

    @PreDestroy
    public void destroy() {
        System.out.println("Im inside destroy...");
    }
}

Я надеюсь, что вы уже знаете это.


registerShutdownHook () в веб-приложении:

В веб-приложении DispatcherServlet / ContextListener создает ApplicationContext и закрывает контекст при завершении работы сервера. Вам не нужно явно вызывать context.close()или context.registerShutdownHook().

Когда сервер отключится, @PreDestoryметоды вашего компонента будут уведомлены автоматически.

Автор: Kalyan Размещён: 29.05.2014 04:22

5 плюса

В веб-приложениях вы можете использовать функцию, ServletContextListenerкоторая срабатывает при развертывании и развертывании вашего приложения:

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:

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");
    //...
}
Автор: Luiggi Mendoza Размещён: 29.05.2014 03:02

2 плюса

Используя Spring 3+, вы можете добавить ContextCleanupListener в контекст приложения.

Зарегистрируйте слушателя при запуске следующим образом (вы можете предпочесть использовать конфигурацию xml, но то же самое применимо)

package com.myapp

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;

import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.ContextCleanupListener;
import org.springframework.web.context.ContextLoaderListener;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;

public class MyWebApplicationInitializer implements WebApplicationInitializer {

    @Override
    public void onStartup(ServletContext servletContext)
            throws ServletException {
        WebApplicationContext appContext = getContext();


        servletContext.addListener(new ContextLoaderListener(appContext));

        // line adding an implementation of ContextCleanupListener
        servletContext.addListener(new MyWebApplicationCleanupListener());

        ServletRegistration.Dynamic dispatcher = servletContext.addServlet("DispatcherServlet", new DispatcherServlet(appContext));
            dispatcher.setLoadOnStartup(1);
            dispatcher.addMapping("/");
    }

    private AnnotationConfigWebApplicationContext getContext() { 
        AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
        context.setConfigLocation("com.myapp");
        return context;
    }
} 

Реализация 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 попадет в отладчик, если вы установите точку останова там.

Автор: John Deverall Размещён: 07.01.2015 04:15

0 плюса

@Luiggi Mendoza ответ начинает работать, когда я добавляю запись в web.xml.

<web-app ...>
   <listener>
    <listener-class>
             com....MyServletContextListener
        </listener-class>
   </listener>
</web-app>

вы можете видеть трассировку стека при инициализации / уведомлении объекта слушателя котом; что намного раньше весны.

com....MyServletContextListener.init(nothing but calling @PostConstruct)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.apache.catalina.core.DefaultInstanceManager.postConstruct(DefaultInstanceManager.java:203)
    at org.apache.catalina.core.DefaultInstanceManager.postConstruct(DefaultInstanceManager.java:188)
    at org.apache.catalina.core.DefaultInstanceManager.newInstance(DefaultInstanceManager.java:143)
    at org.apache.catalina.core.DefaultInstanceManager.newInstance(DefaultInstanceManager.java:119)
    at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4649)
    at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5189)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
    at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:724)
    at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:700)
    at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:734)
    at org.apache.catalina.startup.HostConfig.deployWAR(HostConfig.java:952)
    at org.apache.catalina.startup.HostConfig$DeployWar.run(HostConfig.java:1823)
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)

Но важно то, что @PreDestroy вызывается сначала Spring, затем после вызова contextDestroyed и снова @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 вызывается только для одноэлементных объектов, недоступных для объектов-прототипов.

Автор: Kanagavelu Sugumar Размещён: 25.05.2017 05:54
Вопросы из категории :
32x32