[ACCEPTED]-Register shutDownHook in web application-ioc-container
registerShutdownHook() in standalone (non-web) application:
The @PreDestroy
annotation is used on bean method to 10 be notified when the bean is being removed 9 from the context or when the context is 8 shutting down.
Shut down event is fired when 7 context.close()
or context.registerShutdownHook()
is invoked.
@Component(value="someBean")
public class SomeBean {
@PreDestroy
public void destroy() {
System.out.println("Im inside destroy...");
}
}
I hope you already know 6 this.
registerShutdownHook() in web application:
In a web application, DispatcherServlet/ContextListener 5 creates the ApplicationContext and it will 4 close the context when the server shutdown. You 3 don't need to explicitly invoke context.close()
or context.registerShutdownHook()
.
When the 2 server shutdown, @PreDestory
methods on your bean will 1 be notified automatically.
In web applications, you can use a ServletContextListener
which 3 fires when your application is deployed 2 and undeployed:
public class MyServletContextListener implements ServletContextListener {
public void contextInitialized(ServletContextEvent sce) {
//application is being deployed
}
public void contextDestroyed(ServletContextEvent sce) {
//application is being undeployed
}
}
You can access to your Spring 1 beans by retrieving the current Spring context:
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");
//...
}
Using Spring 3+ you can add a ContextCleanupListener 7 to the application context.
Register your 6 listener at startup like so (you might prefer 5 to use xml config but the same applies)
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;
}
}
Implementation of ContextCleanupListener that runs your shutdown code:
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();
}
}
When 4 you run up say tomcat for example, and press 3 CTRL + C to shut it down, you'll immediately 2 see the contextDestroyed method be hit in 1 the debugger if you put a breakpoint there.
@Luiggi Mendoza answer is started working 15 when i add entry in web.xml.
<web-app ...>
<listener>
<listener-class>
com....MyServletContextListener
</listener-class>
</listener>
</web-app>
you can see 14 the stack trace of initialising/notifying 13 the listener object by the tomcat; which 12 is much before spring does.
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)
But important 11 thing is @PreDestroy called first by Spring, then 10 after contextDestroyed is called and again 9 @PreDestroy called by non-spring thread.
So 8 if you want to complete some work; on that 7 time if you want to ensure other resource 6 thread are available then hold this @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();
}
}
Just 5 know that the below is one more way of getting 4 the @postConstruct hook within the class.
@Autowired
public void setApplicationContext(ApplicationContext applicationContext) {
applicationContext.getBean("myRelatedClass", MyRelatedClass.class);
}
One 3 more thing is @PreDestroy is called only 2 for singleton objects not available for 1 prototype objects.
More Related questions
We use cookies to improve the performance of the site. By staying on our site, you agree to the terms of use of cookies.