英文:
Getting BeanCreationNotAllowedException on spring graceful shutdown
问题
My spring boot application uses spring boot graceful shutdown setting. In the app I'm having queue listeners in the separate threads. Everything gets shut down correctly except that every now and then I get error 'BeanCreationNotAllowedException Singleton bean creation not allowed while singletons of this factory are in destruction (Do not request a bean from a BeanFactory in a destroy method implementation!)'. It happens because in my listener I'm calling beanFactory.getBean but the bean destroy was already initiated, hence the error.
Is there any way to make spring boot wait longer with destroying of the beans?
英文:
My spring boot application uses spring boot graceful shutdown setting. In the app I'm having queue listeners in the separate threads. Everything gets shut down correctly except that every now and then I get error BeanCreationNotAllowedException Singleton bean creation not allowed while singletons of this factory are in destruction (Do not request a bean from a BeanFactory in a destroy method implementation!)
. It happens because in my listener I'm calling beanFactory.getBean but the bean destroy was already initiated, hence the error.
Is there any way to make spring boot wait longer with destroying of the beans?
答案1
得分: 0
This issue arises when a shutdown signal is received and Spring is in the process of closing down the ApplicationContext and destroying the beans. However, in parallel, there might be some tasks in other threads that still require beans from the BeanFactory.
One way to handle this situation is to use a SmartLifecycle
interface. This interface has a getPhase()
method that can be used to control the order in which beans are started and stopped.
To accomplish, you can to the following:
- Implement
SmartLifecycle
interface for the bean that has your queue listeners. It should also include logic in the stop() method to shut down the queue listeners gracefully. - For the
getPhase()
method, return a negative value (like -1). This will make sure that your listeners get stopped before any other beans.
@Component
public class QueueListenerManager implements SmartLifecycle {
private volatile boolean running = false;
@Override
public void start() {
running = true;
// Add logic to start the listeners
}
@Override
public void stop() {
// Add logic to gracefully shutdown the listeners
running = false;
}
@Override
public boolean isRunning() {
return running;
}
@Override
public int getPhase() {
return -1;
}
}
start()
method will start the queue listeners.stop()
method will shut down the queue listeners.isRunning()
method will provide the current status.getPhase()
method is important as it controls the order of stopping beans. Beans are stopped in descending order of their phase value and in our case it's -1, so it will stop before beans with phase values 0 or greater.
Remember that the beans that your listeners depend on should not implement SmartLifecycle or if they do, they should have phase values greater than or equal to zero to ensure they get destroyed after the listeners. also make sure that your Spring Boot application has graceful shutdown enabled,
server.shutdown=graceful
This will ensure that Spring Boot waits for all the SmartLifecycle
beans to stop before proceeding with shutdown.
英文:
This issue arises when a shutdown signal is received and Spring is in the process of closing down the ApplicationContext and destroying the beans. However, in parallel, there might be some tasks in other threads that still require beans from the BeanFactory.
One way to handle this situation is to use a SmartLifecycle
interface. This interface has a getPhase()
method that can be used to control the order in which beans are started and stopped.
To accomplish, you can to the following:
- Implement
SmartLifecycle
interface for the bean that has your queue
listeners. It should also include logic in the stop() method to shut
down the queue listeners gracefully. - For the
getPhase()
method, return a negative value (like -1). This
will make sure that your listeners get stopped before any other
beans.
@Component
public class QueueListenerManager implements SmartLifecycle {
private volatile boolean running = false;
@Override
public void start() {
running = true;
// Add logic to start the listeners
}
@Override
public void stop() {
// Add logic to gracefully shutdown the listeners
running = false;
}
@Override
public boolean isRunning() {
return running;
}
@Override
public int getPhase() {
return -1;
}
}
start()
method will start the queue listeners.stop()
method will shut down the queue listeners.isRunning()
method will provide the current status.getPhase()
method is important as it controls the order of stopping
beans. Beans are stopped in descending order of their phase value
and in our case it's -1, so it will stop before beans with phase
values 0 or greater.
Remember that the beans that your listeners depend on should not implement SmartLifecycle or if they do, they should have phase values greater than or equal to zero to ensure they get destroyed after the listeners. also make sure that your Spring Boot application has graceful shutdown enabled,
server.shutdown=graceful
This will ensure that Spring Boot waits for all the SmartLifecycle
beans to stop before proceeding with shutdown.
答案2
得分: 0
I made it work. I'm using ApplicationListener and adding Thread.sleep on shutdown. This is executed before spring starts actual shutdown so it delays the destruction of the beans.
@Component
@RequiredArgsConstructor
public class GracefulShutdownListener implements ApplicationListener
private long shutdownDelayInMilliseconds = 3000;
@Override
public void onApplicationEvent(ContextClosedEvent event) {
// here I can trigger any additional cleanup
try {
Thread.sleep(shutdownDelayInMilliseconds);
} catch (InterruptedException interruptedException) {
Thread.currentThread().interrupt();
}
}
}
英文:
I made it work. I'm using ApplicationListener and adding Thread.sleep on shutdown. This is executed before spring starts actual shutdown so it delays the destruction of the beans.
@Component
@RequiredArgsConstructor
public class GracefulShutdownListener implements ApplicationListener<ContextClosedEvent> {
private long shutdownDelayInMiliseconds = 3000;
@Override
public void onApplicationEvent(ContextClosedEvent event) {
// here I can trigger any additional cleanup
try {
Thread.sleep(shutdownDelayInMiliseconds);
} catch (InterruptedException interruptedException) {
Thread.currentThread().interrupt();
}
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论