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;
Related
I have a complex enterprise environment with multiple projects depending on each other. Configuration is handled by spring and includes crazy number imports and what not.
Looks like by default Spring is OK with constructing a bean with the same name more than once. Particularly, in case of multiple Spring contexts. Each context its own instance of the same singleton bean. Singleton is not really a singleton in Spring architects' minds...
Unfortunately, in my case there's a bean that can never be created more than once.
Is there a way to enforce Spring checking upon the bean whether it's been created already and not to try to call its constructor again?
Particularly, the bean creates ehcache's CacheManager inside and fails because CacheManager with the same name can't be created twice.
<bean id="cacheService" class="somepackage.CacheServiceImpl">
<constructor-arg index="0" value="/somepackage/ehcache.xml" />
</bean>
I don't have control over the CacheServiceImpl code. I can only change configuration around it.
Different Spring application contexts don't know about each other. As far as each context is concerned, your object is a singleton. However, it sounds like you don't want there to be multiple contexts.
How are you creating contexts? Your application should create a single instance of ApplicationContext (probably in main or somewhere nearby). Anything else that needs an application context should have it injected or be made ApplicationContextAware.
http://docs.spring.io/spring/docs/current/spring-framework-reference/html/beans.html#beans-factory-instantiation
You mention a "complex enterprise environment". What's worked best for us where I work is having a single project manage Spring. Assuming all your projects are being run in the same application (otherwise Spring can't really help you), there's likely some project that starts everything off. For us, that's the project that is built into a war and deployed to our server.
I figured it out finally. The reason for loading the context twice was a hidden error occurring during the first context loading. A long and boring explanation below.
Context is supposed to be loaded during first invocation of spring method DefaultTestContext.getApplicationContext().
There's a class DefaultCacheAwareContextLoaderDelegate, which is responsible for actual loading the context once and caching it for future uses. The method code is below:
#Override
public ApplicationContext loadContext(MergedContextConfiguration mergedContextConfiguration) {
synchronized (this.contextCache) {
ApplicationContext context = this.contextCache.get(mergedContextConfiguration);
if (context == null) {
try {
context = loadContextInternal(mergedContextConfiguration);
if (logger.isDebugEnabled()) {
logger.debug(String.format("Storing ApplicationContext in cache under key [%s]",
mergedContextConfiguration));
}
this.contextCache.put(mergedContextConfiguration, context);
}
catch (Exception ex) {
throw new IllegalStateException("Failed to load ApplicationContext", ex);
}
}
else {
if (logger.isDebugEnabled()) {
logger.debug(String.format("Retrieved ApplicationContext from cache with key [%s]",
mergedContextConfiguration));
}
}
this.contextCache.logStatistics();
return context;
}
}
Obviously, when a Throwable other than Exception gets thrown during loadContextInternal() invocation, the application context doesn't get put in the cache.
Apparently, even when a single JUnit test is run getApplicationContext() method is called more than once with an expectation that second time it won't need to be loaded again since already cached.
If an Error is thrown during first load it gets buried and JUnit/Spring continues with the test until it calls getApplicationContext() for the second time. That's where it catches the exception and crashes because ehcache's doesn't expect CacheManager to be initialized more than once.
I would like to make some clean up on a bean when I shutdown a CDI application. For example, I would like to close an IO connection. Of course, here, the bean is marked as #ApplicationScoped.
To manage this I wrote an extension and observe the BeforeShutdown event, and then I select my bean to call a clean up method :
public void beforeShutdown(#Observes BeforeShutdown beforeShutdown) {
SomeBean obj = CDI.current().select(SomeBean.class).get();
obj.cleanup();
}
My problem is that I have access to a new instance in this method. Not the instance I got in the whole application.
If you want to see this instance problem, I've made a repo on github to show it : https://github.com/hasalex/cdi-extension-demo.
So I have 2 questions :
Why do I get a new instance ?
Is there an other way to cleanup my bean at the end of the application ? (in SE and in WildFly environments)
look here: http://docs.jboss.org/cdi/spec/1.1.EDR1/html/spi.html#provider
11.5.4. BeforeShutdown event
The container must fire a final event after it has finished processing requests and destroyed all contexts.
Maybe you want to use #PreDestroy: http://docs.oracle.com/javaee/6/tutorial/doc/gmgkd.html
Annotate the declaration of the method with the javax.annotation.PreDestroy annotation.
CDI calls this method before starting to destroy the bean.
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);
}
I am using Spring3.1
My application will have kind of bean-manager.
That manager will be able to retrieve request and on each request I need to create new instance of bean dynamically which will be initiate with it's own unique params.
The params will be retrieved via the request method.
This bean must be alive and work asynchronously. (For example it will listen to jms calls, execute methods by demand and so on..)
Moreover I want to have the option to destroy beans also.
Those bean could be resemble as sessions so when the user log off i will destroy those beans.
I understand that I have to create some kind of bean-list or beans pool and manage it with some kind of manager.
How can I create those beans dynamically and have them remain them alive until I destroy them?
Any idea how could I implement such thing?
Well in this sense, the easiest way would be to create a StaticApplicationContext setting its parent context as the common context (the one holding the beans you want to share over all). This you could reach by doing something like:
StaticApplicationContext innerContext = new StaticApplicationContext(parentContext);
after this, you probably want to declare the bean you want to instantiate over Spring in order to attach all the AOP stuff, Autowiring and other functionalities, therefore you will need to do something like:
innerContext.registerSingleton("beanName", beanClass);
After registering you could instantiate the bean like:
innerContext.getBean(beanClass);
Of course there is the implementation of scope Session for spring and therefore I advise you to check the WebApplicationContext documentation, method loadParentContext that you basically pass the ServletContext as paramenter.
I've also found many trouble in creating a bean dynamically at run-time and used it anywhere in application..
Here is complete code
static ApplicationContext appContext = new ClassPathXmlApplicationContext(
new String[] { "Spring-Question.xml" });
static StaticApplicationContext innerContext = new StaticApplicationContext(appContext);
Create the bean and set the values e.g.
innerContext.registerSingleton("beanName", Test.class);
Test test = innerContext.getBean(Test.class);
test.setA(3);
test.setB(4);
Then Re-Use the bean anywhere in application....
Test test = innerContext.getBean(Test.class);
System.out.println(test.setB(4));
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;