My application uses a Spring DefaultMessageListenerContainer to process incoming messages. The main method of the app already registers a shutdown hook.
Question is this: what is the best way to force the application context to shut down?
If I throw a RuntimeException in the message listener, it is handled by the container, and not passed on. Is calling System.exit acceptable? Do I pass along the ApplicationContext to every class that needs to shut down, so I can call close() on it?
You can cast your application context to ConfigurableApplicationContext and call close() on it. At least that's what happens when the context is shut down in a web-application environment, in cases the servlet context is destroyed.
If you want to get ahold of the ApplicationContext, your bean may implement ApplicationContextAware
Another option is to inject (or autowire with #Autowired) the application context:
#Inject
private ApplicationContext ctx;
Related
I have been running in to problems making sure that a spring application context that i am destroying has completely gone away, and cant see the object being garbage collected. When i look at the instance in VisualVM i can see that there are a number of outstanding references to both the context and it's bean factory that remain once the context is closed and destroyed. These all to be in relation to the initial set up of the bean factory (during the refresh method of AbstractApplicationContext) which registers the bean factory and the context with various bean post processors etc.
There do not appear to be any methods on the bean factory or on the application contexts (even the refreshable ones) that do more than remove the lowest level reference to the bean factory. The result is that it appears to be leaking memory, and in certain circumstances preventing the clean re-creation of a context.
I am asking as the software i am working on at the moment may dynamically create / destroy and then re-create the context (as modules are dynamically loaded and unloaded) and the leftover elements of the context and bean factory are causing problems with components such as spring-data-jpa (especially the proxy that binds the repository interfaces to the repository implementations).
Does anyone know of a way whereby i can cleanly and completely remove a context and bean factory without having to completely close down the VM that initially created it?
Having looked into this again recently, i noticed that i was overriding the doClose() method of the context to make sure beans were completely destroyed, but was not calling the super.doClose() method, which meant that LiveBeansView.unregisterApplicationContext() / destroyBeans() / getLifecycleProcessor().onClose() and closeBeanFactory() were not being called.
I added this in, and (most) if not all contexts are now cleanly destroyed and garbage collected. I will assume that any outstanding contexts that are not destroyed are more probably issues in our own code with dangling references.
If you are using Spring's IoC container in a non-web application environment; for example, in a rich client desktop environment; you register a shutdown hook with the JVM. Doing so ensures a graceful shutdown and calls the relevant destroy methods on your singleton beans so that all resources are released. Of course, you must still configure and implement these destroy callbacks correctly.
To register a shutdown hook, you should call the registerShutdownHook() method that is declared on the AbstractApplicationContext class:
Code
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public final class startup {
public static void main(final String[] args) throws Exception {
AbstractApplicationContext ctx
= new ClassPathXmlApplicationContext(new String []{"beans.xml"});
// add a shutdown hook for the above context...
ctx.registerShutdownHook();
// app runs here...
// main method exits, hook is called prior to the app shutting down...
}
}
Call destroy on context and set null to all variables referencing instance of your application context:
AbstractApplicationContext context = new ClassPathXmlApplicationContext(new String []{"beans.xml"});
// ... do your stuff
context.destroy();
context = null;
I have following code in one my team projects:
this.context = new ClassPathXmlApplicationContext("test_spring.xml");
this.task = ((Task)this.context.getBean("task"));
this.context.registerShutdownHook();
this.context.start();
I have never before seen "start" method being called and i dont understand whats the need of start method?
Spring Documentation says:
Start this component. Should not throw an exception if the component is already running.
In the case of a container, this will propagate the start signal to all components that apply.
But i dont understand what does it imply. Can someone explain what can go wrong if start method is not called or how does it helps?
Spring provides a ApplicationListener interface to listen for various ApplicationEvents. One such event is the ContextStartedEvent. You can create a bean of some class that implements ApplicationListener<ContextStartedEvent>.
When you invoke start(), the ApplicationContext will publish such an event and all ApplicationListener beans registered for ContextStartedEvent (they get registered automatically if found in the context) will get notified.
If you don't call start(), they will not get notified.
I have a command line application that uses a Spring-managed bean that's composed of a java ExecutorService created with:
ExecutorService service = Executors.newFixedThreadPool(4);
Now, I want my service to shutdown when my application shuts down, so I made my bean implement the DisposableBean interface and have a destroy method such as:
public void destroy(){
service.shutdown();
}
Then I might be tempted to do something like register a shutdown hook on the Spring context. However I found out (the hard way, i.e., in a pre-production release) that this doesn't work: the shutdown hook doesn't get called before the ExecutorService.shutdown() method is called, causing a classic catch 22 problem (it does get called on interruption, i.e., if I hit Ctrl-C while the application is running). This escaped my unit tests because for some reason it seems to work fine from within JUnit, which is still puzzling me: what does JUnit do differently?
The solution I found so far is to explicitly call ApplicationContext.close() right before I exit my main function. I was wondering if there was a better solution to this and what are the best practices for having flexible thread pools managed by Spring. Also what if my bean is not directly managed by Spring but is created by a bean managed by Spring? Should I just cascade the calls to destroy()? Wouldn't this be very error prone?
I appreciate any comments, suggestions, further reading, RTFMs, magic recipes.
Thanks!
Are you aware that this:
ExecutorService service = Executors.newFixedThreadPool(4);
can be replaced with this:
<bean id="service" class="java.util.concurrent.Executors"
factory-method="newFixedThreadPool" destroy-method="shutdown">
<constructor-arg value="4"/>
</bean>
The spring context then manages, more directly, the shutdown of your executor service--and it can be more easily reused.
Per official Spring documentation, when using annotation-based configuration, for destroyMethod field of #Bean, Spring's default behavior is to automatically invoke public, no-arg methods named close or shutdown when the application context is being closed.
As a convenience to the user, the container will attempt to infer a
destroy method against an object returned from the #Bean method. For
example, given an #Bean method returning an Apache Commons DBCP
BasicDataSource, the container will notice the close() method
available on that object and automatically register it as the
destroyMethod. This 'destroy method inference' is currently limited to
detecting only public, no-arg methods named 'close' or 'shutdown'. The
method may be declared at any level of the inheritance hierarchy and
will be detected regardless of the return type of the #Bean method
(i.e., detection occurs reflectively against the bean instance itself
at creation time).
To re-iterate, this is the default behavior for annotation-driven configuration when a destroy method is not explicitly set. If this behavior is undesired explicitly setting destroy method to an empty string will disable this "feature":
To disable destroy method inference for a particular #Bean, specify an
empty string as the value, e.g. #Bean(destroyMethod=""). Note that the
DisposableBean and the Closeable/AutoCloseable interfaces will
nevertheless get detected and the corresponding destroy/close method
invoked.
On the other hand, when using XML configuration, this is not the default behavior... To achieve parity, destroy-method can be explicitly set to (inferred). Refer to the Destruction callbacks and Default initialization and destroy methods sections in the official docs for details.
Consider using Spring's TaskExecutor, which can be configured with a thread pool.
http://static.springsource.org/spring/docs/3.0.x/reference/scheduling.html
Just want to add the config based ExecutorService bean creation to #Keith's answer
#Bean("fixedThreadPool")
public ExecutorService fixedThreadPool() {
return Executors.newFixedThreadPool(THREAD_POOL_SIZE);
}
When my spring web app shuts down, is there an event I can wireup to somehow that I can perform some cleanup code to empty out some pools etc.
You Could use the following
destroy-method as #amir75 recommends
#PreDestroy annotation
Implement DisposableBean and override destroy method.
All the deatails about these can be found at Disposable Callbacks.
Spring beans have a 'destroy-method' attribute, which will be invoked when you 'close' your context.
<bean id="bean1"
destroy-method="stop"
class="com.example.Bean" />
In order to close it, you'd call the close() method:
http://static.springsource.org/spring/docs/3.0.x/javadoc-api/org/springframework/context/support/AbstractApplicationContext.html#close%28%29
(or just shut down the container if appropriate)
Hope that helps..
Based on the JSR-250 specification the best practice to use in modern spring application is the #PreDestroy annotation since using this approach will decouple your beans from Spring.
The non-Spring way to handle this is to write a class that implements ServletContextListener and do your cleanup in its contextDestroyed method. You'd add your class as a context listener in web.xml.
According to the Spring Boot logback example project, you should close the context to clean up the logging system: https://github.com/spring-projects/spring-boot/commit/10402a651f1ee51704b58985c7ef33619df2c110
Example:
public static void main(String[] args) throws Exception {
SpringApplication.run(SampleLogbackApplication.class, args).close();
}
This question already has answers here:
Execute method on startup in Spring
(13 answers)
Closed 6 years ago.
What is the best way to execute a Java class at application startup using Spring MVC ?
There's not necessarily a "best" way. As usual, there are many ways to do it, and the "best" is whichever fits into your project the best:
Use init-method="..." on a bean element in XML, as cjstehno mentioned
Implement Spring's InitializingBean interface. When deployed in an ApplicationContext, the afterPropertiesSet() method will be called when the bean is created.
Annotate a method on a bean with #PostConstruct. Again, if deployed to an ApplicationContext, the annotated method will be called when the bean is created.
If your bean is more of an infrastructure bean to be tied into the Spring lifecycle, implement ApplicationListener<ContextRefreshedEvent>. The onApplicationEvent(..) method will be called during Spring's startup, and you can do whatever work you need there.
Assuming your context is loaded on startup, create a bean in your spring application context with an init method explicitly called out in the XML config (or implement Springs InitializingBean). If you have lazy-loading enabled you will need to make sure this bean is not lazy.
<bean name="starter" init-method="start" class="com.my.StarterBean" lazy="false" />
(please double-check the params in the docs).
If your context is not loaded on startup you can register an server context listener (part of Servlet API, not Spring).
You can use either implementations:
1) Implement interface InitializingBean. This approach is granted load all your beans then call afterPropertiesSet method.
#Override
public void afterPropertiesSet() throws Exception {
init();
}
2) Using JSR-250's Annotation #PostConstruct. This approach will not wait for spring beans to load.
#PostConstruct
public void init() {
}