In a spring bean is it possible to have a shutdown method which can use transactions?

HappyEngineer picture HappyEngineer · May 5, 2011 · Viewed 26.5k times · Source

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;
}

Answer

Sean Patrick Floyd picture Sean Patrick Floyd · May 5, 2011

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: