started ioc injection guide getting framework example dependency control and java spring tomcat web ioc-container

java - injection - spring ioc example



Registrar shutDownHook en la aplicaciĆ³n web. (4)

¿Cómo podemos registrar el gancho Shutdown en la aplicación web?

¿Hay algún whays para registrarlo en web.xml o en applicationContext.xml?

Sé que si estamos usando la aplicación con clase principal es simple.

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

Pero ¿qué pasa con la aplicación web? Como utiliza ContextListener


En las aplicaciones web, puede usar un ServletContextListener que se ServletContextListener cuando su aplicación se implementa y no se despliega:

public class MyServletContextListener implements ServletContextListener { public void contextInitialized(ServletContextEvent sce) { //application is being deployed } public void contextDestroyed(ServletContextEvent sce) { //application is being undeployed } }

Puedes acceder a tus Spring beans recuperando el contexto Spring actual:

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"); //... }


La respuesta de @Luiggi Mendoza comienza a funcionar cuando agrego una entrada en web.xml.

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

puede ver el seguimiento de la pila de inicializar / notificar el objeto de escucha por el tomcat; que es mucho antes de que llegue la primavera.

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)

Pero lo importante es que primero se llama @PreDestroy por Spring, luego se llama contextDestroyed y nuevamente se llama a @PreDestroy por un hilo no spring.

Así que si quieres completar algún trabajo; en ese momento, si desea asegurarse de que haya otros hilos de recursos disponibles, mantenga presionado este @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(); } }

Solo sepan que lo que sigue es una forma más de obtener el enlace @postConstruct dentro de la clase.

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

Una cosa más es que se llama a @PreDestroy solo para objetos singleton no disponibles para objetos prototipo.


Usando Spring 3+ puede agregar un ContextCleanupListener al contexto de la aplicación.

Registre a su oyente en el inicio como tal (es posible que prefiera utilizar la configuración xml pero se aplica lo mismo)

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; } }

Implementación de ContextCleanupListener que ejecuta su código de apagado:

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(); } }

Cuando se ejecuta, digamos Tomcat, por ejemplo, y presiona CTRL + C para apagarlo, inmediatamente verá que el método contextDestroyed es golpeado en el depurador si coloca un punto de interrupción allí.


registerShutdownHook () en una aplicación independiente (no web):

La anotación @PreDestroy se utiliza en el método de bean para recibir una notificación cuando el bean se está eliminando del contexto o cuando el contexto se está cerrando.

El evento de apagado se context.close() cuando se invoca context.close() o context.registerShutdownHook() .

@Component(value="someBean") public class SomeBean { @PreDestroy public void destroy() { System.out.println("Im inside destroy..."); } }

Espero que ya sepas esto.

registerShutdownHook () en la aplicación web:

En una aplicación web, DispatcherServlet / ContextListener crea ApplicationContext y cerrará el contexto cuando se apague el servidor. No es necesario invocar explícitamente context.close() o context.registerShutdownHook() .

Cuando se apague el servidor, los métodos @PreDestory en su bean se notificarán automáticamente.