In the destroy method of a spring bean I want to execute some queries to clean up some stuff in the database. Spring doesn't seem to allow this by any means I can find.
The error is always something like:
Invocation of destroy method failed on bean with name 'someBean': org.springframework.beans.factory.BeanCreationNotAllowedException: Error creating bean with name 'transactionManager': Singleton bean creation not allowed while the singletons of this factory are in destruction (Do not request a bean from a BeanFactory in a destroy method implementation!)
The following will tell spring to call shutdownDestroy after the bean is no longer needed. But, I get the above error when trying to use transactions.
<bean id="someId" name="someName" class="someClass"
destroy-method="shutdownDestroy"/>
The same is true when I enable common lifecycle annotations using:
<bean class="org.springframework. ... .CommonAnnotationBeanPostProcessor"/>
and then mark the method with @PreDestroy
. That method can't use transactions either.
Is there any way to do this?
EDIT: Thanks! I had the bean implement SmartLifecycle and adding the following and it works very nicely.
private boolean isRunning = false;
@Override
public boolean isAutoStartup() {return true;}
@Override
public boolean isRunning() {return isRunning;}
/** Run as early as possible so the shutdown method can still use transactions. */
@Override
public int getPhase() {return Integer.MIN_VALUE;}
@Override
public void start() {isRunning = true;}
@Override
public void stop(Runnable callback) {
shutdownDestroy();
isRunning = false;
callback.run();
}
@Override
public void stop() {
shutdownDestroy();
isRunning = false;
}
destroyMethod. The optional name of a method to call on the bean instance upon closing the application context, for example a close() method on a JDBC DataSource implementation, or a Hibernate SessionFactory object.
How does Spring generate bean names for classes annotated with @Component that do not specify a name? It uses the short name of the class with the first letter in lowercase.
Spring bean life cycle can be controlled in the following ways. Instantiation by using: InitializingBean callback interface. Custom init() method from the bean configuration file.
A bean is an object that is instantiated, assembled, and otherwise managed by a Spring IoC container. Otherwise, a bean is simply one of many objects in your application. Beans, and the dependencies among them, are reflected in the configuration metadata used by a container.
Interesting Question. I'd say you should be able to do it by letting your bean implement SmartLifeCycle
.
That way, if your int getPhase();
method returns Integer.MAX_VALUE
, it will be among the first to be called when the ApplicationContext
finally shuts down.
Reference:
SmartLifeCycle
javadocsI come across this same issue. After check spring's source code, U can try to implements
public class SomeBean implements ApplicationListener<ContextClosedEvent> {
public void onApplicationEvent(ContextClosedEvent event) {
stopHook();
}
}
onApplicationEvent will be call before bean destory, you can check it on spring's org.springframework.context.support.AbstractApplicationContext#doClose method. I paste it below, so ContextEvent -> LifeCycle -> Bean destory.
try {
// Publish shutdown event.
publishEvent(new ContextClosedEvent(this));
}
catch (Throwable ex) {
logger.warn("Exception thrown from ApplicationListener handling ContextClosedEvent", ex);
}
// Stop all Lifecycle beans, to avoid delays during individual destruction.
try {
getLifecycleProcessor().onClose();
}
catch (Throwable ex) {
logger.warn("Exception thrown from LifecycleProcessor on context close", ex);
}
// Destroy all cached singletons in the context's BeanFactory.
destroyBeans();
// Close the state of this context itself.
closeBeanFactory();
// Let subclasses do some final clean-up if they wish...
onClose();
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With