AbstractApplicationContext refinements (backported from 4.2.2)
Shutdown hook triggers doClose within startupShutdownMonitor; allow for re-refresh and re-close. Issue: SPR-13556 Issue: SPR-13425
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -162,6 +162,9 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
|
||||
/** Parent context */
|
||||
private ApplicationContext parent;
|
||||
|
||||
/** Environment used by this context */
|
||||
private ConfigurableEnvironment environment;
|
||||
|
||||
/** BeanFactoryPostProcessors to apply on refresh */
|
||||
private final List<BeanFactoryPostProcessor> beanFactoryPostProcessors =
|
||||
new ArrayList<BeanFactoryPostProcessor>();
|
||||
@@ -194,10 +197,7 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
|
||||
private ApplicationEventMulticaster applicationEventMulticaster;
|
||||
|
||||
/** Statically specified listeners */
|
||||
private Set<ApplicationListener<?>> applicationListeners = new LinkedHashSet<ApplicationListener<?>>();
|
||||
|
||||
/** Environment used by this context; initialized by {@link #createEnvironment()} */
|
||||
private ConfigurableEnvironment environment;
|
||||
private final Set<ApplicationListener<?>> applicationListeners = new LinkedHashSet<ApplicationListener<?>>();
|
||||
|
||||
|
||||
/**
|
||||
@@ -352,7 +352,7 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
|
||||
* @return the internal LifecycleProcessor (never {@code null})
|
||||
* @throws IllegalStateException if the context has not been initialized yet
|
||||
*/
|
||||
LifecycleProcessor getLifecycleProcessor() {
|
||||
LifecycleProcessor getLifecycleProcessor() throws IllegalStateException {
|
||||
if (this.lifecycleProcessor == null) {
|
||||
throw new IllegalStateException("LifecycleProcessor not initialized - " +
|
||||
"call 'refresh' before invoking lifecycle methods via the context: " + this);
|
||||
@@ -504,6 +504,7 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
|
||||
*/
|
||||
protected void prepareRefresh() {
|
||||
this.startupDate = System.currentTimeMillis();
|
||||
this.closed.set(false);
|
||||
this.active.set(true);
|
||||
|
||||
if (logger.isInfoEnabled()) {
|
||||
@@ -721,11 +722,12 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
|
||||
for (ApplicationListener<?> listener : getApplicationListeners()) {
|
||||
getApplicationEventMulticaster().addApplicationListener(listener);
|
||||
}
|
||||
|
||||
// Do not initialize FactoryBeans here: We need to leave all regular beans
|
||||
// uninitialized to let post-processors apply to them!
|
||||
String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
|
||||
for (String lisName : listenerBeanNames) {
|
||||
getApplicationEventMulticaster().addApplicationListenerBean(lisName);
|
||||
for (String listenerBeanName : listenerBeanNames) {
|
||||
getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -801,7 +803,9 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
|
||||
this.shutdownHook = new Thread() {
|
||||
@Override
|
||||
public void run() {
|
||||
doClose();
|
||||
synchronized (startupShutdownMonitor) {
|
||||
doClose();
|
||||
}
|
||||
}
|
||||
};
|
||||
Runtime.getRuntime().addShutdownHook(this.shutdownHook);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -49,7 +49,7 @@ import static org.junit.Assert.*;
|
||||
* @author Juergen Hoeller
|
||||
* @author Chris Beams
|
||||
*/
|
||||
public final class ClassPathXmlApplicationContextTests {
|
||||
public class ClassPathXmlApplicationContextTests {
|
||||
|
||||
private static final String PATH = "/org/springframework/context/support/";
|
||||
private static final String RESOURCE_CONTEXT = PATH + "ClassPathXmlApplicationContextTests-resource.xml";
|
||||
@@ -82,13 +82,23 @@ public final class ClassPathXmlApplicationContextTests {
|
||||
@Test
|
||||
public void testMultipleConfigLocations() {
|
||||
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(
|
||||
new String[] { FQ_CONTEXT_B, FQ_CONTEXT_C, FQ_CONTEXT_A});
|
||||
FQ_CONTEXT_B, FQ_CONTEXT_C, FQ_CONTEXT_A);
|
||||
assertTrue(ctx.containsBean("service"));
|
||||
assertTrue(ctx.containsBean("logicOne"));
|
||||
assertTrue(ctx.containsBean("logicTwo"));
|
||||
|
||||
// re-refresh (after construction refresh)
|
||||
Service service = (Service) ctx.getBean("service");
|
||||
ctx.refresh();
|
||||
assertTrue(service.isProperlyDestroyed());
|
||||
|
||||
// regular close call
|
||||
service = (Service) ctx.getBean("service");
|
||||
ctx.close();
|
||||
assertTrue(service.isProperlyDestroyed());
|
||||
|
||||
// re-activating and re-closing the context (SPR-13425)
|
||||
ctx.refresh();
|
||||
service = (Service) ctx.getBean("service");
|
||||
ctx.close();
|
||||
assertTrue(service.isProperlyDestroyed());
|
||||
@@ -107,8 +117,7 @@ public final class ClassPathXmlApplicationContextTests {
|
||||
|
||||
@Test
|
||||
public void testSingleConfigLocationWithClass() {
|
||||
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(
|
||||
SIMPLE_CONTEXT, getClass());
|
||||
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(SIMPLE_CONTEXT, getClass());
|
||||
assertTrue(ctx.containsBean("someMessageSource"));
|
||||
ctx.close();
|
||||
}
|
||||
@@ -116,7 +125,7 @@ public final class ClassPathXmlApplicationContextTests {
|
||||
@Test
|
||||
public void testAliasWithPlaceholder() {
|
||||
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(
|
||||
new String[] { FQ_CONTEXT_B, FQ_ALIASED_CONTEXT_C, FQ_CONTEXT_A});
|
||||
FQ_CONTEXT_B, FQ_ALIASED_CONTEXT_C, FQ_CONTEXT_A);
|
||||
assertTrue(ctx.containsBean("service"));
|
||||
assertTrue(ctx.containsBean("logicOne"));
|
||||
assertTrue(ctx.containsBean("logicTwo"));
|
||||
@@ -144,16 +153,14 @@ public final class ClassPathXmlApplicationContextTests {
|
||||
private void checkExceptionFromInvalidValueType(Throwable ex) throws IOException {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
ex.printStackTrace(new PrintStream(baos));
|
||||
String dump = FileCopyUtils.copyToString(
|
||||
new InputStreamReader(new ByteArrayInputStream(baos.toByteArray())));
|
||||
String dump = FileCopyUtils.copyToString(new InputStreamReader(new ByteArrayInputStream(baos.toByteArray())));
|
||||
assertTrue(dump.contains("someMessageSource"));
|
||||
assertTrue(dump.contains("useCodeAsDefaultMessage"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testContextWithInvalidLazyClass() {
|
||||
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(
|
||||
INVALID_CLASS_CONTEXT, getClass());
|
||||
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(INVALID_CLASS_CONTEXT, getClass());
|
||||
assertTrue(ctx.containsBean("someMessageSource"));
|
||||
try {
|
||||
ctx.getBean("someMessageSource");
|
||||
@@ -167,8 +174,7 @@ public final class ClassPathXmlApplicationContextTests {
|
||||
|
||||
@Test
|
||||
public void testContextWithClassNameThatContainsPlaceholder() {
|
||||
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(
|
||||
CLASS_WITH_PLACEHOLDER_CONTEXT, getClass());
|
||||
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(CLASS_WITH_PLACEHOLDER_CONTEXT, getClass());
|
||||
assertTrue(ctx.containsBean("someMessageSource"));
|
||||
assertTrue(ctx.getBean("someMessageSource") instanceof StaticMessageSource);
|
||||
ctx.close();
|
||||
@@ -282,7 +288,7 @@ public final class ClassPathXmlApplicationContextTests {
|
||||
@Test
|
||||
public void testAliasThatOverridesEarlierBean() {
|
||||
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(
|
||||
new String[] {FQ_SIMPLE_CONTEXT, ALIAS_THAT_OVERRIDES_PARENT_CONTEXT});
|
||||
FQ_SIMPLE_CONTEXT, ALIAS_THAT_OVERRIDES_PARENT_CONTEXT);
|
||||
Object myMs = ctx.getBean("myMessageSource");
|
||||
Object someMs2 = ctx.getBean("someMessageSource");
|
||||
assertSame(myMs, someMs2);
|
||||
|
||||
Reference in New Issue
Block a user