How does Lifecycle interface work in Spring? What are "top-level singleton beans"?

java, multithreading, spring

Solution

You should use `SmartLifecycle` instead of `Lifecycle`. Only the former is working as you expected `Lifecycle` to work. Make sure you return true in your `isRunning()` implementation.

I have used `SmartLifecycle` for asynchronous jobs for which it sounds like designed for. I suppose it will work for you but at the same time you may have a look at `ApplicationListener` and events like `ContextStoppedEvent`.

Problem

It is said in Spring javadoc, that "Note that the Lifecycle interface is only supported on top-level singleton beans." Here URL My `LifecycleBeanTest.xml` describes bean as follows: ``` <beans ...> <bean id="lifecycle" class="tests.LifecycleBean"/> </beans> ``` so it looks "topish" and "singletonish" enough. What does it mean? How to make Spring know about my bean implementing `Lifecycle` and do something with it? Suppose my main method looks following in Spring ``` public static void main(String[] args) { new ClassPathXmlApplicationContext("/tests/LifecycleBeanTest.xml").close(); } ``` so, it instantiates context and then closes it immediately. May I create some bean in my configuration, which delays `close()` execution until application do all it's works? So that main method thread wait for application termination? For example, the following bean does not work in way I thought. Neither `start()` not `stop()` is called. ``` package tests; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.context.Lifecycle; public class LifecycleBean implements Lifecycle { private static final Logger log = LoggerFactory.getLogger(LifecycleBean.class); private final Thread thread = new Thread("Lifecycle") { { setDaemon(false); setUncaughtExceptionHandler(new UncaughtExceptionHandler() { @Override public void uncaughtException(Thread t, Throwable e) { log.error("Abnormal thread termination", e); } }); } public void run() { for(int i=0; i<10 && !isInterrupted(); ++i) { log.info("Hearbeat {}", i); try { sleep(1000); } catch (InterruptedException e) { return; } } }; }; @Override public void start() { log.info("Starting bean"); thread.start(); } @Override public void stop() { log.info("Stopping bean"); thread.interrupt(); try { thread.join(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); return; } } @Override public boolean isRunning() { return thread.isAlive(); } } ``` UPDATE 1 I know I can wait for bean in code. It is interesting to hook into Spring itself.

Original source