Introduce ApplicationContextInitializer interface

Designed primarily for use in conjunction with web applications
to provide a convenient mechanism for configuring the container
programmatically.

ApplicationContextInitializer implementations are specified through the
new "contextInitializerClasses" servlet context parameter, then detected
and invoked by ContextLoader in its customizeContext() method.

In any case, the semantics of ApplicationContextInitializer's
initialize(ConfigurableApplicationContext) method require that
invocation occur *prior* to refreshing the application context.

ACI implementations may also implement Ordered/PriorityOrdered and
ContextLoader will sort instances appropriately prior to invocation.

Specifically, this new support provides a straightforward way to
programmatically access the container's Environment for the purpose
of adding, removing or otherwise manipulating PropertySource objects.

See Javadoc for further details.

Also note that ApplicationContextInitializer semantics overlap to
some degree with Servlet 3.0's notion of ServletContainerInitializer
classes. As Spring 3.1 development progresses, we'll likely see
these two come together and further influence one another.
This commit is contained in:
Chris Beams
2011-01-07 09:57:57 +00:00
parent 71e60f4551
commit a7293d2961
6 changed files with 232 additions and 13 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2010 the original author or authors.
* Copyright 2002-2011 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.
@@ -16,15 +16,24 @@
package org.springframework.web.context;
import static org.hamcrest.CoreMatchers.equalTo;
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 static org.junit.Assert.*;
import org.junit.Test;
import org.springframework.beans.BeansException;
import org.springframework.beans.TestBean;
import org.springframework.beans.factory.BeanCreationException;
@@ -33,9 +42,14 @@ import org.springframework.beans.factory.LifecycleBean;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextException;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.PropertySource;
import org.springframework.mock.web.MockServletConfig;
import org.springframework.mock.web.MockServletContext;
import org.springframework.util.StringUtils;
import org.springframework.web.context.support.XmlWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.SimpleWebApplicationContext;
@@ -100,6 +114,39 @@ public final class ContextLoaderTests {
assertEquals("customizeContext() should have been called.", expectedContents, buffer.toString());
}
@Test
public void testContextLoaderListenerWithRegisteredContextConfigurer() {
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()}));
ContextLoaderListener listener = new ContextLoaderListener();
listener.contextInitialized(new ServletContextEvent(sc));
WebApplicationContext wac = ContextLoaderListener.getCurrentWebApplicationContext();
TestBean testBean = wac.getBean(TestBean.class);
assertThat(testBean.getName(), equalTo("testName"));
assertThat(wac.getServletContext().getAttribute("initialized"), notNullValue());
}
@Test
public void testContextLoaderListenerWithUnkownContextConfigurer() {
MockServletContext sc = new MockServletContext("");
// config file doesn't matter. just a placeholder
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()}));
ContextLoaderListener listener = new ContextLoaderListener();
try {
listener.contextInitialized(new ServletContextEvent(sc));
fail("expected exception");
} catch (IllegalArgumentException ex) {
assertTrue(ex.getMessage().contains("not assignable"));
}
}
@Test
public void testContextLoaderWithDefaultContextAndParent() throws Exception {
MockServletContext sc = new MockServletContext("");
@@ -257,4 +304,33 @@ public final class ContextLoaderTests {
}
}
private static class TestContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
public void initialize(ConfigurableApplicationContext applicationContext) {
ConfigurableEnvironment environment = applicationContext.getEnvironment();
environment.getPropertySources().addFirst(new PropertySource<Object>("testPropertySource") {
@Override
public Object getProperty(String key) {
return "name".equals(key) ? "testName" : null;
}
});
}
}
private static class TestWebContextInitializer implements ApplicationContextInitializer<ConfigurableWebApplicationContext> {
public void initialize(ConfigurableWebApplicationContext applicationContext) {
ServletContext ctx = applicationContext.getServletContext(); // type-safe access to servlet-specific methods
ctx.setAttribute("initialized", true);
}
}
private static interface UnknownApplicationContext extends ConfigurableApplicationContext {
void unheardOf();
}
private static class UnknownContextInitializer implements ApplicationContextInitializer<UnknownApplicationContext> {
public void initialize(UnknownApplicationContext applicationContext) {
applicationContext.unheardOf();
}
}
}

View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean class="org.springframework.beans.TestBean">
<constructor-arg value="${name}"/>
</bean>
<bean class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer"/>
</beans>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
</beans>