diff --git a/spring-web/src/main/java/org/springframework/web/context/ContextLoader.java b/spring-web/src/main/java/org/springframework/web/context/ContextLoader.java index 9f45686fef..16da9161d3 100644 --- a/spring-web/src/main/java/org/springframework/web/context/ContextLoader.java +++ b/spring-web/src/main/java/org/springframework/web/context/ContextLoader.java @@ -77,8 +77,8 @@ import org.springframework.util.StringUtils; * *
As of Spring 3.1, {@code ContextLoader} supports injecting the root web * application context via the {@link #ContextLoader(WebApplicationContext)} - * constructor, allowing for programmatic configuration in Servlet 3.0+ environments. See - * {@link org.springframework.web.WebApplicationInitializer} for usage examples. + * constructor, allowing for programmatic configuration in Servlet 3.0+ environments. + * See {@link org.springframework.web.WebApplicationInitializer} for usage examples. * * @author Juergen Hoeller * @author Colin Sampaleanu @@ -90,26 +90,12 @@ import org.springframework.util.StringUtils; */ public class ContextLoader { - /** - * Config param for the root WebApplicationContext implementation class to use: {@value} - * @see #determineContextClass(ServletContext) - * @see #createWebApplicationContext(ServletContext, ApplicationContext) - */ - public static final String CONTEXT_CLASS_PARAM = "contextClass"; - /** * Config param for the root WebApplicationContext id, * to be used as serialization id for the underlying BeanFactory: {@value} */ public static final String CONTEXT_ID_PARAM = "contextId"; - /** - * Config param for which {@link ApplicationContextInitializer} classes to use - * for initializing the web application context: {@value} - * @see #customizeContext(ServletContext, ConfigurableWebApplicationContext) - */ - public static final String CONTEXT_INITIALIZER_CLASSES_PARAM = "contextInitializerClasses"; - /** * Name of servlet context parameter (i.e., {@value}) that can specify the * config location for the root context, falling back to the implementation's @@ -118,6 +104,27 @@ public class ContextLoader { */ public static final String CONFIG_LOCATION_PARAM = "contextConfigLocation"; + /** + * Config param for the root WebApplicationContext implementation class to use: {@value} + * @see #determineContextClass(ServletContext) + * @see #createWebApplicationContext(ServletContext, ApplicationContext) + */ + public static final String CONTEXT_CLASS_PARAM = "contextClass"; + + /** + * Config param for {@link ApplicationContextInitializer} classes to use + * for initializing the root web application context: {@value} + * @see #customizeContext(ServletContext, ConfigurableWebApplicationContext) + */ + public static final String CONTEXT_INITIALIZER_CLASSES_PARAM = "contextInitializerClasses"; + + /** + * Config param for global {@link ApplicationContextInitializer} classes to use + * for initializing all web application contexts in the current application: {@value} + * @see #customizeContext(ServletContext, ConfigurableWebApplicationContext) + */ + public static final String GLOBAL_INITIALIZER_CLASSES_PARAM = "globalInitializerClasses"; + /** * Optional servlet context parameter (i.e., "{@code locatorFactorySelector}") * used only when obtaining a parent context using the default implementation @@ -146,6 +153,12 @@ public class ContextLoader { */ public static final String LOCATOR_FACTORY_KEY_PARAM = "parentContextKey"; + /** + * Any number of these characters are considered delimiters between + * multiple values in a single init-param String value. + */ + private static final String INIT_PARAM_DELIMITERS = ",; \t\n"; + /** * Name of the class path resource (relative to the ContextLoader class) * that defines ContextLoader's default strategy names. @@ -373,14 +386,71 @@ public class ContextLoader { } wac.setServletContext(sc); - String initParameter = sc.getInitParameter(CONFIG_LOCATION_PARAM); - if (initParameter != null) { - wac.setConfigLocation(initParameter); + String configLocationParam = sc.getInitParameter(CONFIG_LOCATION_PARAM); + if (configLocationParam != null) { + wac.setConfigLocation(configLocationParam); } + + // The wac environment's #initPropertySources will be called in any case when the context + // is refreshed; do it eagerly here to ensure servlet property sources are in place for + // use in any post-processing or initialization that occurs below prior to #refresh + ConfigurableEnvironment env = wac.getEnvironment(); + if (env instanceof ConfigurableWebEnvironment) { + ((ConfigurableWebEnvironment) env).initPropertySources(sc, null); + } + customizeContext(sc, wac); wac.refresh(); } + /** + * Customize the {@link ConfigurableWebApplicationContext} created by this + * ContextLoader after config locations have been supplied to the context + * but before the context is refreshed. + *
The default implementation {@linkplain #determineContextInitializerClasses(ServletContext) + * determines} what (if any) context initializer classes have been specified through + * {@linkplain #CONTEXT_INITIALIZER_CLASSES_PARAM context init parameters} and + * {@linkplain ApplicationContextInitializer#initialize invokes each} with the + * given web application context. + *
Any {@code ApplicationContextInitializers} implementing
+ * {@link org.springframework.core.Ordered Ordered} or marked with @{@link
+ * org.springframework.core.annotation.Order Order} will be sorted appropriately.
+ * @param sc the current servlet context
+ * @param wac the newly created application context
+ * @see #createWebApplicationContext(ServletContext, ApplicationContext)
+ * @see #CONTEXT_INITIALIZER_CLASSES_PARAM
+ * @see ApplicationContextInitializer#initialize(ConfigurableApplicationContext)
+ */
+ protected void customizeContext(ServletContext sc, ConfigurableWebApplicationContext wac) {
+ List The default implementation {@linkplain #determineContextInitializerClasses(ServletContext)
- * determines} what (if any) context initializer classes have been specified through
- * {@linkplain #CONTEXT_INITIALIZER_CLASSES_PARAM context init parameters} and
- * {@linkplain ApplicationContextInitializer#initialize invokes each} with the
- * given web application context.
- * Any {@code ApplicationContextInitializers} implementing
- * {@link org.springframework.core.Ordered Ordered} or marked with @{@link
- * org.springframework.core.annotation.Order Order} will be sorted appropriately.
- * @param servletContext the current servlet context
- * @param applicationContext the newly created application context
- * @see #createWebApplicationContext(ServletContext, ApplicationContext)
- * @see #CONTEXT_INITIALIZER_CLASSES_PARAM
- * @see ApplicationContextInitializer#initialize(ConfigurableApplicationContext)
- */
- protected void customizeContext(ServletContext servletContext, ConfigurableWebApplicationContext applicationContext) {
- List See also {@link #postProcessWebApplicationContext}, which is designed to allow
- * subclasses (as opposed to end-users) to modify the application context, and is
- * called immediately after this method.
- * @param wac the configured WebApplicationContext (not refreshed yet)
- * @see #createWebApplicationContext
- * @see #postProcessWebApplicationContext
- * @see ConfigurableApplicationContext#refresh()
- */
- @SuppressWarnings("unchecked")
- protected void applyInitializers(ConfigurableApplicationContext wac) {
- if (this.contextInitializerClasses != null) {
- String[] initializerClassNames =
- StringUtils.tokenizeToStringArray(this.contextInitializerClasses, INIT_PARAM_DELIMITERS);
- for (String initializerClassName : initializerClassNames) {
- ApplicationContextInitializer See also {@link #postProcessWebApplicationContext}, which is designed to allow
+ * subclasses (as opposed to end-users) to modify the application context, and is
+ * called immediately before this method.
+ * @param wac the configured WebApplicationContext (not refreshed yet)
+ * @see #createWebApplicationContext
+ * @see #postProcessWebApplicationContext
+ * @see ConfigurableApplicationContext#refresh()
+ */
+ protected void applyInitializers(ConfigurableApplicationContext wac) {
+ String globalClassNames = getServletContext().getInitParameter(ContextLoader.GLOBAL_INITIALIZER_CLASSES_PARAM);
+ if (globalClassNames != null) {
+ for (String className : StringUtils.tokenizeToStringArray(globalClassNames, INIT_PARAM_DELIMITERS)) {
+ this.contextInitializers.add(loadInitializer(className, wac));
+ }
+ }
+
+ if (this.contextInitializerClasses != null) {
+ for (String className : StringUtils.tokenizeToStringArray(this.contextInitializerClasses, INIT_PARAM_DELIMITERS)) {
+ this.contextInitializers.add(loadInitializer(className, wac));
+ }
+ }
+
+ AnnotationAwareOrderComparator.sort(this.contextInitializers);
+ for (ApplicationContextInitializer The default implementation returns
diff --git a/spring-webmvc/src/test/java/org/springframework/web/context/ContextLoaderTests.java b/spring-webmvc/src/test/java/org/springframework/web/context/ContextLoaderTests.java
index 15a7e36fea..b8e8630a5d 100644
--- a/spring-webmvc/src/test/java/org/springframework/web/context/ContextLoaderTests.java
+++ b/spring-webmvc/src/test/java/org/springframework/web/context/ContextLoaderTests.java
@@ -16,30 +16,17 @@
package org.springframework.web.context;
-import static org.hamcrest.CoreMatchers.equalTo;
-import static org.hamcrest.CoreMatchers.is;
-import static org.hamcrest.CoreMatchers.notNullValue;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertThat;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
import java.io.FileNotFoundException;
import java.io.IOException;
-
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import org.junit.Test;
+
import org.springframework.beans.BeansException;
-import org.springframework.tests.sample.beans.TestBean;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.BeanDefinitionStoreException;
-import org.springframework.tests.sample.beans.LifecycleBean;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextException;
@@ -50,11 +37,17 @@ import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.PropertySource;
import org.springframework.mock.web.test.MockServletConfig;
import org.springframework.mock.web.test.MockServletContext;
+import org.springframework.tests.sample.beans.LifecycleBean;
+import org.springframework.tests.sample.beans.TestBean;
import org.springframework.util.StringUtils;
+import org.springframework.web.context.support.WebApplicationContextUtils;
import org.springframework.web.context.support.XmlWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.SimpleWebApplicationContext;
+import static org.hamcrest.CoreMatchers.*;
+import static org.junit.Assert.*;
+
/**
* Tests for {@link ContextLoader} and {@link ContextLoaderListener}.
*
@@ -70,14 +63,14 @@ public final class ContextLoaderTests {
public void testContextLoaderListenerWithDefaultContext() {
MockServletContext sc = new MockServletContext("");
sc.addInitParameter(ContextLoader.CONFIG_LOCATION_PARAM,
- "/org/springframework/web/context/WEB-INF/applicationContext.xml "
- + "/org/springframework/web/context/WEB-INF/context-addition.xml");
+ "/org/springframework/web/context/WEB-INF/applicationContext.xml " +
+ "/org/springframework/web/context/WEB-INF/context-addition.xml");
ServletContextListener listener = new ContextLoaderListener();
ServletContextEvent event = new ServletContextEvent(sc);
listener.contextInitialized(event);
WebApplicationContext context = (WebApplicationContext) sc.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
assertTrue("Correct WebApplicationContext exposed in ServletContext", context instanceof XmlWebApplicationContext);
- assertTrue(ContextLoader.getCurrentWebApplicationContext() instanceof XmlWebApplicationContext);
+ assertTrue(WebApplicationContextUtils.getRequiredWebApplicationContext(sc) instanceof XmlWebApplicationContext);
LifecycleBean lb = (LifecycleBean) context.getBean("lifecycle");
assertTrue("Has father", context.containsBean("father"));
assertTrue("Has rod", context.containsBean("rod"));
@@ -88,7 +81,7 @@ public final class ContextLoaderTests {
listener.contextDestroyed(event);
assertTrue("Destroyed", lb.isDestroyed());
assertNull(sc.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE));
- assertNull(ContextLoader.getCurrentWebApplicationContext());
+ assertNull(WebApplicationContextUtils.getWebApplicationContext(sc));
}
/**
@@ -104,12 +97,12 @@ public final class ContextLoaderTests {
final MockServletContext sc = new MockServletContext("");
sc.addInitParameter(ContextLoader.CONFIG_LOCATION_PARAM,
"/org/springframework/web/context/WEB-INF/applicationContext.xml");
- final ServletContextListener listener = new ContextLoaderListener() {
+ ServletContextListener listener = new ContextLoaderListener() {
@Override
- protected void customizeContext(ServletContext servletContext, ConfigurableWebApplicationContext applicationContext) {
- assertNotNull("The ServletContext should not be null.", servletContext);
- assertEquals("Verifying that we received the expected ServletContext.", sc, servletContext);
- assertFalse("The ApplicationContext should not yet have been refreshed.", applicationContext.isActive());
+ protected void customizeContext(ServletContext sc, ConfigurableWebApplicationContext wac) {
+ assertNotNull("The ServletContext should not be null.", sc);
+ assertEquals("Verifying that we received the expected ServletContext.", sc, sc);
+ assertFalse("The ApplicationContext should not yet have been refreshed.", wac.isActive());
buffer.append(expectedContents);
}
};
@@ -118,16 +111,45 @@ public final class ContextLoaderTests {
}
@Test
- public void testContextLoaderListenerWithRegisteredContextInitializer() {
+ public void testContextLoaderListenerWithLocalContextInitializers() {
MockServletContext sc = new MockServletContext("");
sc.addInitParameter(ContextLoader.CONFIG_LOCATION_PARAM,
"org/springframework/web/context/WEB-INF/ContextLoaderTests-acc-context.xml");
- sc.addInitParameter(ContextLoader.CONTEXT_INITIALIZER_CLASSES_PARAM,
- StringUtils.arrayToCommaDelimitedString(
- new Object[]{TestContextInitializer.class.getName(), TestWebContextInitializer.class.getName()}));
+ sc.addInitParameter(ContextLoader.CONTEXT_INITIALIZER_CLASSES_PARAM, StringUtils.arrayToCommaDelimitedString(
+ new Object[] {TestContextInitializer.class.getName(), TestWebContextInitializer.class.getName()}));
ContextLoaderListener listener = new ContextLoaderListener();
listener.contextInitialized(new ServletContextEvent(sc));
- WebApplicationContext wac = ContextLoaderListener.getCurrentWebApplicationContext();
+ WebApplicationContext wac = WebApplicationContextUtils.getRequiredWebApplicationContext(sc);
+ TestBean testBean = wac.getBean(TestBean.class);
+ assertThat(testBean.getName(), equalTo("testName"));
+ assertThat(wac.getServletContext().getAttribute("initialized"), notNullValue());
+ }
+
+ @Test
+ public void testContextLoaderListenerWithGlobalContextInitializers() {
+ MockServletContext sc = new MockServletContext("");
+ sc.addInitParameter(ContextLoader.CONFIG_LOCATION_PARAM,
+ "org/springframework/web/context/WEB-INF/ContextLoaderTests-acc-context.xml");
+ sc.addInitParameter(ContextLoader.GLOBAL_INITIALIZER_CLASSES_PARAM, StringUtils.arrayToCommaDelimitedString(
+ new Object[] {TestContextInitializer.class.getName(), TestWebContextInitializer.class.getName()}));
+ ContextLoaderListener listener = new ContextLoaderListener();
+ listener.contextInitialized(new ServletContextEvent(sc));
+ WebApplicationContext wac = WebApplicationContextUtils.getRequiredWebApplicationContext(sc);
+ TestBean testBean = wac.getBean(TestBean.class);
+ assertThat(testBean.getName(), equalTo("testName"));
+ assertThat(wac.getServletContext().getAttribute("initialized"), notNullValue());
+ }
+
+ @Test
+ public void testContextLoaderListenerWithMixedContextInitializers() {
+ MockServletContext sc = new MockServletContext("");
+ sc.addInitParameter(ContextLoader.CONFIG_LOCATION_PARAM,
+ "org/springframework/web/context/WEB-INF/ContextLoaderTests-acc-context.xml");
+ sc.addInitParameter(ContextLoader.CONTEXT_INITIALIZER_CLASSES_PARAM, TestContextInitializer.class.getName());
+ sc.addInitParameter(ContextLoader.GLOBAL_INITIALIZER_CLASSES_PARAM, TestWebContextInitializer.class.getName());
+ ContextLoaderListener listener = new ContextLoaderListener();
+ listener.contextInitialized(new ServletContextEvent(sc));
+ WebApplicationContext wac = WebApplicationContextUtils.getRequiredWebApplicationContext(sc);
TestBean testBean = wac.getBean(TestBean.class);
assertThat(testBean.getName(), equalTo("testName"));
assertThat(wac.getServletContext().getAttribute("initialized"), notNullValue());
@@ -136,7 +158,7 @@ public final class ContextLoaderTests {
@Test
public void testRegisteredContextInitializerCanAccessServletContextParamsViaEnvironment() {
MockServletContext sc = new MockServletContext("");
- // config file doesn't matter. just a placeholder
+ // config file doesn't matter - just a placeholder
sc.addInitParameter(ContextLoader.CONFIG_LOCATION_PARAM,
"/org/springframework/web/context/WEB-INF/empty-context.xml");
@@ -153,12 +175,13 @@ public final class ContextLoaderTests {
sc.addInitParameter(ContextLoader.CONFIG_LOCATION_PARAM,
"/org/springframework/web/context/WEB-INF/empty-context.xml");
sc.addInitParameter(ContextLoader.CONTEXT_INITIALIZER_CLASSES_PARAM,
- StringUtils.arrayToCommaDelimitedString(new Object[]{UnknownContextInitializer.class.getName()}));
+ StringUtils.arrayToCommaDelimitedString(new Object[] {UnknownContextInitializer.class.getName()}));
ContextLoaderListener listener = new ContextLoaderListener();
try {
listener.contextInitialized(new ServletContextEvent(sc));
fail("expected exception");
- } catch (IllegalArgumentException ex) {
+ }
+ catch (IllegalArgumentException ex) {
assertTrue(ex.getMessage().contains("not assignable"));
}
}
@@ -321,7 +344,9 @@ public final class ContextLoaderTests {
}
}
+
private static class TestContextInitializer implements ApplicationContextInitializer