복붙노트

[SPRING] 웹 응용 프로그램에 shutDownHook 등록

SPRING

웹 응용 프로그램에 shutDownHook 등록

웹 응용 프로그램에서 시스템 종료 훅을 등록하는 방법은 무엇입니까?

web.xml 또는 applicationContext.xml에 등록 할 수있는 방법이 있습니까?

메인 클래스의 애플리케이션을 사용한다면 간단하다는 것을 알고 있습니다.

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

하지만 웹 응용 프로그램은 어떻습니까? ContextListener를 사용하므로

해결법

  1. ==============================

    1.독립형 (비 웹) 응용 프로그램에서 registerShutdownHook () :

    독립형 (비 웹) 응용 프로그램에서 registerShutdownHook () :

    @PreDestroy 어노테이션은 Bean이 컨텍스트에서 제거 될 때 또는 컨텍스트가 종료 될 때 통지되도록 Bean 메소드에 사용됩니다.

    종료 이벤트는 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 ()을 명시 적으로 호출 할 필요가 없습니다.

    서버가 종료되면 Bean의 @PreDestory 메소드가 자동으로 통지됩니다.

  2. ==============================

    2.웹 응용 프로그램에서 응용 프로그램을 배포 및 배포 취소 할 때 발생하는 ServletContextListener를 사용할 수 있습니다.

    웹 응용 프로그램에서 응용 프로그램을 배포 및 배포 취소 할 때 발생하는 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");
        //...
    }
    
  3. ==============================

    3.Spring 3+를 사용하면 ContextCleanupListener를 애플리케이션 컨텍스트에 추가 할 수있다.

    Spring 3+를 사용하면 ContextCleanupListener를 애플리케이션 컨텍스트에 추가 할 수있다.

    그렇게 시작할 때 리스너를 등록하십시오 (xml config를 사용하는 것을 선호 할 수도 있지만 동일하게 적용됩니다)

    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 메서드가 실행되는 것을 볼 수 있습니다.

  4. ==============================

    4.@Luiggi Mendoza 응답은 web.xml에 항목을 추가 할 때 작동하기 시작합니다.

    @Luiggi Mendoza 응답은 web.xml에 항목을 추가 할 때 작동하기 시작합니다.

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

    당신은 tomcat에 의해 리스너 객체를 초기화 / 통지하는 스택 추적을 볼 수 있습니다; 봄이 오기 훨씬 전에.

    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는 프로토 타입 객체에 사용할 수없는 싱글 톤 객체에만 호출됩니다.

  5. from https://stackoverflow.com/questions/23936162/register-shutdownhook-in-web-application by cc-by-sa and MIT license