ContextLoader中setContextInitializers(ApplicationContextInitializer<?>... initializers)的思考

来源:互联网 发布:剑客软件 编辑:程序博客网 时间:2024/06/08 04:59

最近查看了ContextLoader的源代码,涉及到了contextInitializerClasses参数,由于自己的项目没有用到该参数,对此产生了好奇,参考网上资料,整理一下:

ContextLoader中部分代码:

public class ContextLoader {public static final String CONTEXT_ID_PARAM = "contextId";public static final String CONFIG_LOCATION_PARAM = "contextConfigLocation";public static final String CONTEXT_CLASS_PARAM = "contextClass";public static final String CONTEXT_INITIALIZER_CLASSES_PARAM = "contextInitializerClasses";public static final String GLOBAL_INITIALIZER_CLASSES_PARAM = "globalInitializerClasses";public static final String LOCATOR_FACTORY_SELECTOR_PARAM = "locatorFactorySelector";public static final String LOCATOR_FACTORY_KEY_PARAM = "parentContextKey";private static final String INIT_PARAM_DELIMITERS = ",; \t\n";private static final String DEFAULT_STRATEGIES_PATH = "ContextLoader.properties";public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {......                //初始化时调用此方法configureAndRefreshWebApplicationContext(cwac, servletContext);......}protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac, ServletContext sc) {......                //使用contextConfigLocation参数配置String configLocationParam = sc.getInitParameter(CONFIG_LOCATION_PARAM);if (configLocationParam != null) {wac.setConfigLocation(configLocationParam);}......                //ContextLoader创建ConfigurableWebApplicationContextcustomizeContext(sc, wac);wac.refresh();}protected void customizeContext(ServletContext sc, ConfigurableWebApplicationContext wac) {                //处理ApplicationContextInitializer的地方List<Class<ApplicationContextInitializer<ConfigurableApplicationContext>>> initializerClasses = determineContextInitializerClasses(sc);for (Class<ApplicationContextInitializer<ConfigurableApplicationContext>> initializerClass : initializerClasses) {......this.contextInitializers.add(BeanUtils.instantiateClass(initializerClass));}AnnotationAwareOrderComparator.sort(this.contextInitializers);for (ApplicationContextInitializer<ConfigurableApplicationContext> initializer : this.contextInitializers) {initializer.initialize(wac);}}        //返回由globalInitializerClasses和contextInitializerClasses定义的ApplicationContextInitializer列表protected List<Class<ApplicationContextInitializer<ConfigurableApplicationContext>>> determineContextInitializerClasses(ServletContext servletContext) {List<Class<ApplicationContextInitializer<ConfigurableApplicationContext>>> classes =             new ArrayList<Class<ApplicationContextInitializer<ConfigurableApplicationContext>>>();//globalInitializerClassesString globalClassNames = servletContext.getInitParameter(GLOBAL_INITIALIZER_CLASSES_PARAM);if (globalClassNames != null) {for (String className : StringUtils.tokenizeToStringArray(globalClassNames, INIT_PARAM_DELIMITERS)) {classes.add(loadInitializerClass(className));}}//contextInitializerClassesString localClassNames = servletContext.getInitParameter(CONTEXT_INITIALIZER_CLASSES_PARAM);if (localClassNames != null) {for (String className : StringUtils.tokenizeToStringArray(localClassNames, INIT_PARAM_DELIMITERS)) {classes.add(loadInitializerClass(className));}}return classes;}@SuppressWarnings("unchecked")private Class<ApplicationContextInitializer<ConfigurableApplicationContext>> loadInitializerClass(String className) {try {Class<?> clazz = ClassUtils.forName(className, ClassUtils.getDefaultClassLoader());Assert.isAssignable(ApplicationContextInitializer.class, clazz);return (Class<ApplicationContextInitializer<ConfigurableApplicationContext>>) clazz;} catch (ClassNotFoundException ex) {throw new ApplicationContextException("Failed to load context initializer class [" + className + "]", ex);}}}
涉及到的ApplicationContextInitializer类:

package org.springframework.context;/** * Callback interface for initializing a Spring {@link ConfigurableApplicationContext} * prior to being {@linkplain ConfigurableApplicationContext#refresh() refreshed}. * * <p>Typically used within web applications that require some programmatic initialization * of the application context. For example, registering property sources or activating * profiles against the {@linkplain ConfigurableApplicationContext#getEnvironment() * context's environment}. See {@code ContextLoader} and {@code FrameworkServlet} support * for declaring a "contextInitializerClasses" context-param and init-param, respectively. * * <p>{@code ApplicationContextInitializer} processors are encouraged to detect * whether Spring's {@link org.springframework.core.Ordered Ordered} interface has been * implemented or if the @{@link org.springframework.core.annotation.Order Order} * annotation is present and to sort instances accordingly if so prior to invocation. *  * 回调接口,用于ConfigurableApplicationContext.refresh()刷新前,初始化 * Spring的ConfigurableApplicationContext。 * * 通常用在web应用程序中需要对应用程序上下文做一些程序初始化时。例如:注册property资源文件或者 * 激活对上下文环境的环境配置文件。分别参见ContextLoader和FrameworkServlet,分别通过在<context-param> * 和<init-param>中声明contextInitializerClasses参数来的支持。 *  * ApplicationContextInitializer处理器检测是否实现了Ordered接口或者是否有@Order注解的实例存在,以此 * 按声明的顺序进行调用。 * * @author Chris Beams * @since 3.1 * @see org.springframework.web.context.ContextLoader#customizeContext * @see org.springframework.web.context.ContextLoader#CONTEXT_INITIALIZER_CLASSES_PARAM * @see org.springframework.web.servlet.FrameworkServlet#setContextInitializerClasses * @see org.springframework.web.servlet.FrameworkServlet#applyInitializers */public interface ApplicationContextInitializer<C extends ConfigurableApplicationContext> {/** * 初始化给定的应用程序上下文。 * @param applicationContext the application to configure */void initialize(C applicationContext);}
由此可知,可以通过ApplicationContextInitializer更改ConfigurableApplicationContext子类的行为。

举个例子:

XmlWebApplicationContext.setAllowBeanDefinitionOverriding()其默认值为true。如果把此值设置为false,怎么解决?

有两个思路:
1、写org.springframework.web.context.ContextLoaderListener和org.springframework.web.servlet.DispatcherServlet的子类:
在相应的方法中进行设置context.setAllowBeanDefinitionOverriding(false); 
这种方法如果处理不好,会引起很多麻烦,不推荐。
2、根据ApplicationContextInitializer接口的说明,通过参数配置来改变applicationContext的行为:
1)首先定义一个ApplicationContextInitializer的子类:

public class MyApplicationContextInitializer implements ApplicationContextInitializer<XmlWebApplicationContext> {  public void initialize(XmlWebApplicationContext applicationContext) {                //XmlWebApplicationContext是ConfigurableApplicationContext的子类//由此可以改变applicationContext的默认行为。applicationContext.setAllowBeanDefinitionOverriding(false);}  }  

2)在配置文件中引用
由ContextLoaderListener调用的配置方式:

<context-param><param-name>contextClass</param-name><param-value>org.springframework.web.context.support.XmlWebApplicationContext</param-value></context-param><context-param><param-name>contextConfigLocation</param-name><param-value>classpath*:applicationContext.xml</param-value></context-param><context-param><param-name>contextInitializerClasses</param-name>  <param-value>MyApplicationContextInitializer</param-value></context-param><listener><listener-class>org.springframework.web.context.ContextLoaderListener</listener-class></listener>

由DispatcherServlet调用的配置方式

<servlet><servlet-name>dispatcherServlet</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><load-on-startup>1</load-on-startup><init-param><param-name>contextConfigLocation</param-name><param-value>classpath:spring-servlet.xml</param-value></init-param><init-param>   <param-name>contextInitializerClasses</param-name>  <param-value>MyApplicationContextInitializer</param-value></init-param>  </servlet>
通过这种方式,可以改变XmlWebApplicationContext其他的属性,如果有必要的话。



1 0
原创粉丝点击