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
d
You can examine AbstractApplicationContext.doClose()
method and see that no interruption of application context closing has been provided by the Spring developers
protected void doClose() {
boolean actuallyClose;
synchronized (this.activeMonitor) {
actuallyClose = this.active && !this.closed;
this.closed = true;
}
if (actuallyClose) {
if (logger.isInfoEnabled()) {
logger.info("Closing " + this);
}
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();
synchronized (this.activeMonitor) {
this.active = false;
}
}
}
So you can't prevent the application context from closing.
If you are using Spring test context framework with JUnit, I think you can use it to test services that implement Lifecycle, I used the technique from one of the internal Spring tests
Slightly modified LifecycleBean(I've added waitForTermination()
method):
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();
waitForTermination();
}
@Override
public boolean isRunning() {
return thread.isAlive();
}
public void waitForTermination() {
try {
thread.join();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return;
}
}
}
Test class:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:Test-context.xml")
public class LifecycleBeanTest {
@Autowired
LifecycleBean bean;
Lifecycle appContextLifeCycle;
@Autowired
public void setLifeCycle(ApplicationContext context){
this.appContextLifeCycle = (Lifecycle)context;
}
@Test
public void testLifeCycle(){
//"start" application context
appContextLifeCycle.start();
bean.waitForTermination();
}
}
Test-context.xml content:
P.S. starting and stopping the context is not a thing you may want to do many times on the same application context, so you may need to put @DirtiesContext
annotation on your test methods for the best results.
DefaultLifecycleProcessor uses beanFactory.getBeanNamesForType(Lifecycle.class, false, false);
to retrieve the list of the beans implementing Lifecycle
From getBeanNamesForType javadoc:
NOTE: This method introspects top-level beans only. It does not check nested beans which might match the specified type as well.
So this method does not list the inner beans (they were called nested when only xml configuration was available - they are declared as nested bean xml elements).
Consider the following example from the documentation
Tony
51
Start() and Stop() are merely events that are propagated by the application context they are not connected with lifetime of the application context, for example you can implement a download manager with some service beans - when the user hits "pause" button, you will broadcast the "stop" event, then when the user hits "start" button, you can resume the processing by broadcasting the "start" event. Spring is usable here, because it dispatches events in the proper order.