1818
1919import java .io .IOException ;
2020import java .util .ArrayList ;
21- import java .util .Collections ;
2221import java .util .List ;
2322import java .util .Map ;
2423import java .util .Properties ;
7877 *
7978 * <p>As of Spring 3.1, {@code ContextLoader} supports injecting the root web
8079 * application context via the {@link #ContextLoader(WebApplicationContext)}
81- * constructor, allowing for programmatic configuration in Servlet 3.0+ environments. See
82- * {@link org.springframework.web.WebApplicationInitializer} for usage examples.
80+ * constructor, allowing for programmatic configuration in Servlet 3.0+ environments.
81+ * See {@link org.springframework.web.WebApplicationInitializer} for usage examples.
8382 *
8483 * @author Juergen Hoeller
8584 * @author Colin Sampaleanu
9190 */
9291public class ContextLoader {
9392
93+ /**
94+ * Config param for the root WebApplicationContext id,
95+ * to be used as serialization id for the underlying BeanFactory: {@value}
96+ */
97+ public static final String CONTEXT_ID_PARAM = "contextId" ;
98+
99+ /**
100+ * Name of servlet context parameter (i.e., {@value}) that can specify the
101+ * config location for the root context, falling back to the implementation's
102+ * default otherwise.
103+ * @see org.springframework.web.context.support.XmlWebApplicationContext#DEFAULT_CONFIG_LOCATION
104+ */
105+ public static final String CONFIG_LOCATION_PARAM = "contextConfigLocation" ;
106+
94107 /**
95108 * Config param for the root WebApplicationContext implementation class to use: {@value}
96109 * @see #determineContextClass(ServletContext)
@@ -99,25 +112,18 @@ public class ContextLoader {
99112 public static final String CONTEXT_CLASS_PARAM = "contextClass" ;
100113
101114 /**
102- * Config param for the root WebApplicationContext id,
103- * to be used as serialization id for the underlying BeanFactory: {@value}
104- */
105- public static final String CONTEXT_ID_PARAM = "contextId" ;
106-
107- /**
108- * Config param for which {@link ApplicationContextInitializer} classes to use
109- * for initializing the web application context: {@value}
115+ * Config param for {@link ApplicationContextInitializer} classes to use
116+ * for initializing the root web application context: {@value}
110117 * @see #customizeContext(ServletContext, ConfigurableWebApplicationContext)
111118 */
112119 public static final String CONTEXT_INITIALIZER_CLASSES_PARAM = "contextInitializerClasses" ;
113120
114121 /**
115- * Name of servlet context parameter (i.e., {@value}) that can specify the
116- * config location for the root context, falling back to the implementation's
117- * default otherwise.
118- * @see org.springframework.web.context.support.XmlWebApplicationContext#DEFAULT_CONFIG_LOCATION
122+ * Config param for global {@link ApplicationContextInitializer} classes to use
123+ * for initializing all web application contexts in the current application: {@value}
124+ * @see #customizeContext(ServletContext, ConfigurableWebApplicationContext)
119125 */
120- public static final String CONFIG_LOCATION_PARAM = "contextConfigLocation " ;
126+ public static final String GLOBAL_INITIALIZER_CLASSES_PARAM = "globalInitializerClasses " ;
121127
122128 /**
123129 * Optional servlet context parameter (i.e., "{@code locatorFactorySelector}")
@@ -147,6 +153,12 @@ public class ContextLoader {
147153 */
148154 public static final String LOCATOR_FACTORY_KEY_PARAM = "parentContextKey" ;
149155
156+ /**
157+ * Any number of these characters are considered delimiters between
158+ * multiple values in a single init-param String value.
159+ */
160+ private static final String INIT_PARAM_DELIMITERS = ",; \t \n " ;
161+
150162 /**
151163 * Name of the class path resource (relative to the ContextLoader class)
152164 * that defines ContextLoader's default strategy names.
@@ -381,14 +393,71 @@ protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicati
381393 }
382394
383395 wac .setServletContext (sc );
384- String initParameter = sc .getInitParameter (CONFIG_LOCATION_PARAM );
385- if (initParameter != null ) {
386- wac .setConfigLocation (initParameter );
396+ String configLocationParam = sc .getInitParameter (CONFIG_LOCATION_PARAM );
397+ if (configLocationParam != null ) {
398+ wac .setConfigLocation (configLocationParam );
387399 }
400+
401+ // The wac environment's #initPropertySources will be called in any case when the context
402+ // is refreshed; do it eagerly here to ensure servlet property sources are in place for
403+ // use in any post-processing or initialization that occurs below prior to #refresh
404+ ConfigurableEnvironment env = wac .getEnvironment ();
405+ if (env instanceof ConfigurableWebEnvironment ) {
406+ ((ConfigurableWebEnvironment ) env ).initPropertySources (sc , null );
407+ }
408+
388409 customizeContext (sc , wac );
389410 wac .refresh ();
390411 }
391412
413+ /**
414+ * Customize the {@link ConfigurableWebApplicationContext} created by this
415+ * ContextLoader after config locations have been supplied to the context
416+ * but before the context is <em>refreshed</em>.
417+ * <p>The default implementation {@linkplain #determineContextInitializerClasses(ServletContext)
418+ * determines} what (if any) context initializer classes have been specified through
419+ * {@linkplain #CONTEXT_INITIALIZER_CLASSES_PARAM context init parameters} and
420+ * {@linkplain ApplicationContextInitializer#initialize invokes each} with the
421+ * given web application context.
422+ * <p>Any {@code ApplicationContextInitializers} implementing
423+ * {@link org.springframework.core.Ordered Ordered} or marked with @{@link
424+ * org.springframework.core.annotation.Order Order} will be sorted appropriately.
425+ * @param sc the current servlet context
426+ * @param wac the newly created application context
427+ * @see #createWebApplicationContext(ServletContext, ApplicationContext)
428+ * @see #CONTEXT_INITIALIZER_CLASSES_PARAM
429+ * @see ApplicationContextInitializer#initialize(ConfigurableApplicationContext)
430+ */
431+ protected void customizeContext (ServletContext sc , ConfigurableWebApplicationContext wac ) {
432+ List <Class <ApplicationContextInitializer <ConfigurableApplicationContext >>> initializerClasses =
433+ determineContextInitializerClasses (sc );
434+ if (initializerClasses .isEmpty ()) {
435+ // no ApplicationContextInitializers have been declared -> nothing to do
436+ return ;
437+ }
438+
439+ ArrayList <ApplicationContextInitializer <ConfigurableApplicationContext >> initializerInstances =
440+ new ArrayList <ApplicationContextInitializer <ConfigurableApplicationContext >>();
441+
442+ for (Class <ApplicationContextInitializer <ConfigurableApplicationContext >> initializerClass : initializerClasses ) {
443+ Class <?> initializerContextClass =
444+ GenericTypeResolver .resolveTypeArgument (initializerClass , ApplicationContextInitializer .class );
445+ if (initializerContextClass != null ) {
446+ Assert .isAssignable (initializerContextClass , wac .getClass (), String .format (
447+ "Could not add context initializer [%s] since its generic parameter [%s] " +
448+ "is not assignable from the type of application context used by this " +
449+ "context loader [%s]: " , initializerClass .getName (), initializerContextClass .getName (),
450+ wac .getClass ().getName ()));
451+ }
452+ initializerInstances .add (BeanUtils .instantiateClass (initializerClass ));
453+ }
454+
455+ AnnotationAwareOrderComparator .sort (initializerInstances );
456+ for (ApplicationContextInitializer <ConfigurableApplicationContext > initializer : initializerInstances ) {
457+ initializer .initialize (wac );
458+ }
459+ }
460+
392461 /**
393462 * Return the WebApplicationContext implementation class to use, either the
394463 * default XmlWebApplicationContext or a custom context class if specified.
@@ -426,80 +495,38 @@ protected Class<?> determineContextClass(ServletContext servletContext) {
426495 * @param servletContext current servlet context
427496 * @see #CONTEXT_INITIALIZER_CLASSES_PARAM
428497 */
429- @ SuppressWarnings ("unchecked" )
430498 protected List <Class <ApplicationContextInitializer <ConfigurableApplicationContext >>>
431499 determineContextInitializerClasses (ServletContext servletContext ) {
432- String classNames = servletContext . getInitParameter ( CONTEXT_INITIALIZER_CLASSES_PARAM );
500+
433501 List <Class <ApplicationContextInitializer <ConfigurableApplicationContext >>> classes =
434- new ArrayList <Class <ApplicationContextInitializer <ConfigurableApplicationContext >>>();
435- if (classNames != null ) {
436- for (String className : StringUtils .tokenizeToStringArray (classNames , "," )) {
437- try {
438- Class <?> clazz = ClassUtils .forName (className , ClassUtils .getDefaultClassLoader ());
439- Assert .isAssignable (ApplicationContextInitializer .class , clazz ,
440- "class [" + className + "] must implement ApplicationContextInitializer" );
441- classes .add ((Class <ApplicationContextInitializer <ConfigurableApplicationContext >>)clazz );
442- }
443- catch (ClassNotFoundException ex ) {
444- throw new ApplicationContextException (
445- "Failed to load context initializer class [" + className + "]" , ex );
446- }
447- }
448- }
449- return classes ;
450- }
502+ new ArrayList <Class <ApplicationContextInitializer <ConfigurableApplicationContext >>>();
451503
452- /**
453- * Customize the {@link ConfigurableWebApplicationContext} created by this
454- * ContextLoader after config locations have been supplied to the context
455- * but before the context is <em>refreshed</em>.
456- * <p>The default implementation {@linkplain #determineContextInitializerClasses(ServletContext)
457- * determines} what (if any) context initializer classes have been specified through
458- * {@linkplain #CONTEXT_INITIALIZER_CLASSES_PARAM context init parameters} and
459- * {@linkplain ApplicationContextInitializer#initialize invokes each} with the
460- * given web application context.
461- * <p>Any {@code ApplicationContextInitializers} implementing
462- * {@link org.springframework.core.Ordered Ordered} or marked with @{@link
463- * org.springframework.core.annotation.Order Order} will be sorted appropriately.
464- * @param servletContext the current servlet context
465- * @param applicationContext the newly created application context
466- * @see #createWebApplicationContext(ServletContext, ApplicationContext)
467- * @see #CONTEXT_INITIALIZER_CLASSES_PARAM
468- * @see ApplicationContextInitializer#initialize(ConfigurableApplicationContext)
469- */
470- protected void customizeContext (ServletContext servletContext , ConfigurableWebApplicationContext applicationContext ) {
471- List <Class <ApplicationContextInitializer <ConfigurableApplicationContext >>> initializerClasses =
472- determineContextInitializerClasses (servletContext );
473- if (initializerClasses .size () == 0 ) {
474- // no ApplicationContextInitializers have been declared -> nothing to do
475- return ;
504+ String globalClassNames = servletContext .getInitParameter (GLOBAL_INITIALIZER_CLASSES_PARAM );
505+ if (globalClassNames != null ) {
506+ for (String className : StringUtils .tokenizeToStringArray (globalClassNames , INIT_PARAM_DELIMITERS )) {
507+ classes .add (loadInitializerClass (className ));
508+ }
476509 }
477510
478- Class <?> contextClass = applicationContext .getClass ();
479- ArrayList <ApplicationContextInitializer <ConfigurableApplicationContext >> initializerInstances =
480- new ArrayList <ApplicationContextInitializer <ConfigurableApplicationContext >>();
481-
482- for (Class <ApplicationContextInitializer <ConfigurableApplicationContext >> initializerClass : initializerClasses ) {
483- Class <?> initializerContextClass =
484- GenericTypeResolver .resolveTypeArgument (initializerClass , ApplicationContextInitializer .class );
485- if (initializerContextClass != null ) {
486- Assert .isAssignable (initializerContextClass , contextClass , String .format (
487- "Could not add context initializer [%s] as its generic parameter [%s] " +
488- "is not assignable from the type of application context used by this " +
489- "context loader [%s]: " , initializerClass .getName (), initializerContextClass .getName (),
490- contextClass .getName ()));
511+ String localClassNames = servletContext .getInitParameter (CONTEXT_INITIALIZER_CLASSES_PARAM );
512+ if (localClassNames != null ) {
513+ for (String className : StringUtils .tokenizeToStringArray (localClassNames , INIT_PARAM_DELIMITERS )) {
514+ classes .add (loadInitializerClass (className ));
491515 }
492- initializerInstances .add (BeanUtils .instantiateClass (initializerClass ));
493516 }
494517
495- ConfigurableEnvironment env = applicationContext .getEnvironment ();
496- if (env instanceof ConfigurableWebEnvironment ) {
497- ((ConfigurableWebEnvironment )env ).initPropertySources (servletContext , null );
498- }
518+ return classes ;
519+ }
499520
500- Collections .sort (initializerInstances , new AnnotationAwareOrderComparator ());
501- for (ApplicationContextInitializer <ConfigurableApplicationContext > initializer : initializerInstances ) {
502- initializer .initialize (applicationContext );
521+ @ SuppressWarnings ("unchecked" )
522+ private Class <ApplicationContextInitializer <ConfigurableApplicationContext >> loadInitializerClass (String className ) {
523+ try {
524+ Class <?> clazz = ClassUtils .forName (className , ClassUtils .getDefaultClassLoader ());
525+ Assert .isAssignable (ApplicationContextInitializer .class , clazz );
526+ return (Class <ApplicationContextInitializer <ConfigurableApplicationContext >>) clazz ;
527+ }
528+ catch (ClassNotFoundException ex ) {
529+ throw new ApplicationContextException ("Failed to load context initializer class [" + className + "]" , ex );
503530 }
504531 }
505532
0 commit comments