Register shutDownHook in web application
Solution 1
registerShutdownHook() in standalone (non-web) application:
The @PreDestroy
annotation is used on bean method to be notified when the bean is being removed from the context or when the context is shutting down.
Shut down event is fired when 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 this.
registerShutdownHook() in web application:
In a web application, DispatcherServlet/ContextListener creates the ApplicationContext and it will close the context when the server shutdown. You don't need to explicitly invoke context.close()
or context.registerShutdownHook()
.
When the server shutdown, @PreDestory
methods on your bean will be notified automatically.
Solution 2
In web applications, you can use a ServletContextListener
which fires when your application is deployed 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 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");
//...
}
Solution 3
Using Spring 3+ you can add a ContextCleanupListener to the application context.
Register your listener at startup like so (you might prefer 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 you run up say tomcat for example, and press CTRL + C to shut it down, you'll immediately see the contextDestroyed method be hit in the debugger if you put a breakpoint there.
Related videos on Youtube
Comments
-
slisnychyi almost 4 years
How we can registerShutdown hook in web application?
Is there any whays to register it in web.xml or in applicationContext.xml?
I know that if we are using application with main class it's simple.
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml"); context.registerShutdownHook();
But what about web application? As it uses ContextListener
-
Kanagavelu Sugumar almost 7 yearsHave you got any solution ?
-
-
slisnychyi almost 10 yearsThank you, for answer. Could you tell, how I can get object that stands for SPRING context. On which I can call context.registerShutdownHook();
-
Kalyan almost 10 yearsUse can use @PreDestroy method in bean.
-
Luiggi Mendoza almost 10 years@Javakid that won't work if you want to only fire a process when the application is being undeployed.
-
Kalyan almost 10 years@Luiggi Thanks. Why do you think it wouldn't work and when do you think
@PreDestory
will be invoked? I just tried to stop and undeploy the application, the method gets notified. -
Luiggi Mendoza almost 10 years@Javakid try changing the scope of the bean to
prototype
and retrieve it two or more times. -
Kalyan almost 10 years:) Sorry, but you still didn't give an explanation. ServletContextListener is used for global cleanup task and @PreDestroy is used for bean specific cleanup task. You can choose either of them depending on your need. When using
prototype
, @PreDestroy will be invoked whenever the bean is removed from the context. Not many people I know useprototype
correctly. So I can't say how you meant to use it. Anyway I'll leave it here. -
Luiggi Mendoza almost 10 years@Javakid I don't need to give an explanation if you understand what will happen with beans as prototype: the process will be invoked per instance removed from the context. And people don't use
prototype
(correctly or not) mainly because the default scope for beans issingleton
. Since OP haven't provided a way the process should behave nor any scenario for it, this can be the best option. Maybe the clean-up process needs several beans and an orchestration of these. -
Kalyan almost 10 yearsI kindly like to let you know that I don't agree with stmt
Maybe the clean-up process needs several beans and an orchestration of these
. That means you are not following Separation of concern law. Each bean should perform its own cleanup task. However, there may be an extreme scenario where global cleanup task might be required. -
Luiggi Mendoza almost 10 years@Javakid when maintaining legacy applications, specially very old applications, there's no separation of concern law (just look at a monolithic architecture the application has), so this is the available option. The only thing I'm sure here is that this is the safest approach in case you want a single specific place to fire any clean up process in general web applications. Framework specific benefits (or backdoors to your own doom) are not covered in my answer, and it's good to know about
@PreDestruct
for this case. Just to note,@PreDestruct
is not from Spring but from Java EE. -
Kalyan almost 10 yearsThanks for your effort. Although @PreDestory is from Java EE, it is very much part of Spring annotation. There is a reason for not introducing new annotation for XML "destroy" attribute alternative and Spring community decided to use the existing annotation in Java EE.
-
Luiggi Mendoza almost 10 years@Javakid that wasn't the meaning of the last sentence of my comment. Anyway, looks like we both know what we're doing. Hopefully, OP will understand and decide the best option as well :)
-
Kalyan almost 10 years+1 for your effort lol... Have a good night...:) The last message went away before I could finish.
-
slisnychyi almost 10 yearsThanks for your suggestion. But this approach is not working. I added necessary function @Override public void contextInitialized(ServletContextEvent sce) { ServletContext context = sce.getServletContext(); WebApplicationContext springContext = WebApplicationContextUtils.getWebApplicationContext(context); ClassPathXmlApplicationContext applicationContext = (ClassPathXmlApplicationContext) springContext.getParent(); applicationContext.registerShutdownHook(); } But when I call applicationContext.registerShutDownHook().I got NullPointer excaption
-
Philippe over 8 yearsExcellent response. The @PreDestroy was the key! Thanks a lot :-)
-
Anand Kadhi over 8 years@Kalyan :: @ Predestroy is called for Bean destruction, that means if the bean is not singleton this would be invoked multiple times whenever the container removes the bean.
-
mre almost 7 years@Anandj.Kadhi that's not true - docs.spring.io/spring/docs/3.1.x/spring-framework-reference/…
-
Kanagavelu Sugumar almost 7 yearsI think i am missing to do this "In order to receive these notification events, the implementation class must be either declared in the deployment descriptor of the web application, annotated with WebListener, or registered via one of the addListener methods defined on ServletContext."
-
Kanagavelu Sugumar almost 7 years@LuiggiMendoza Your Solution is working, i have missed adding entry in the web.xml :( Thank you!! very much.
-
Kanagavelu Sugumar almost 7 yearsIs there a way only calling PreDestroy, because PostConstruct is called by ServletContextListener, but getting NPE because of; some of fields are not autowired at that time. Please help.
-
Luiggi Mendoza almost 7 years@KanagaveluSugumar Spring will wire everything for you. If something cannot be wired is because it was lazy wiring or the bean couldn't been created, and you have to check why wasn't created.
-
Kanagavelu Sugumar almost 7 yearsIn your code sample given the variable
springContext
is null we are getting. This is same even @slisnychyi mentioned in this comment section. Also there is TYPO in the samplectx.getBean()
shouldspringContext.getBean()