ApplicationContextInitializer机制

Posted 恒奇恒毅

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ApplicationContextInitializer机制相关的知识,希望对你有一定的参考价值。

定义

/**
 * 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.
 *
 * @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> 

	/**
	 * Initialize the given application context.
	 * @param applicationContext the application to configure
	 */
	void initialize(C applicationContext);


ApplicationContextInitializer 提供了对ConfigurableApplicationContext初始化配置的能力。属于一个回调接口,主要用在web环境中,比如初始化property sources或者active profiles。

在哪儿调用?

  • ContextLoader
    ContextLoaderListener的父类ContextLoader#customizeContext方法中
	protected void customizeContext(ServletContext sc, ConfigurableWebApplicationContext wac) 
		List<Class<ApplicationContextInitializer<ConfigurableApplicationContext>>> initializerClasses =
				determineContextInitializerClasses(sc);

		for (Class<ApplicationContextInitializer<ConfigurableApplicationContext>> initializerClass : initializerClasses) 
			Class<?> initializerContextClass =
					GenericTypeResolver.resolveTypeArgument(initializerClass, ApplicationContextInitializer.class);
			if (initializerContextClass != null && !initializerContextClass.isInstance(wac)) 
				throw new ApplicationContextException(String.format(
						"Could not apply context initializer [%s] since its generic parameter [%s] " +
						"is not assignable from the type of application context used by this " +
						"context loader: [%s]", initializerClass.getName(), initializerContextClass.getName(),
						wac.getClass().getName()));
			
			this.contextInitializers.add(BeanUtils.instantiateClass(initializerClass));
		

		AnnotationAwareOrderComparator.sort(this.contextInitializers);
		for (ApplicationContextInitializer<ConfigurableApplicationContext> initializer : this.contextInitializers) 
			initializer.initialize(wac);
		
	


	protected List<Class<ApplicationContextInitializer<ConfigurableApplicationContext>>>
			determineContextInitializerClasses(ServletContext servletContext) 

		List<Class<ApplicationContextInitializer<ConfigurableApplicationContext>>> classes =
				new ArrayList<Class<ApplicationContextInitializer<ConfigurableApplicationContext>>>();

		String globalClassNames = servletContext.getInitParameter(GLOBAL_INITIALIZER_CLASSES_PARAM);
		if (globalClassNames != null) 
			for (String className : StringUtils.tokenizeToStringArray(globalClassNames, INIT_PARAM_DELIMITERS)) 
				classes.add(loadInitializerClass(className));
			
		

		String 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;
	

ServletContext的初始化参数globalInitializerClasses、contextInitializerClasse获取。

  • DelegatingApplicationContextInitializer
    该类代理了其他ApplicationContextInitializer,它从ConfigurableApplicationContext的环境变量context.initializer.classes中获取其他的ApplicationContextInitializer。而DelegatingApplicationContextInitializer已经定义在了spring.factories中,说明我们可以直接往context设置环境变量context.initializer.classes即可。

  • FrameworkServlet
    org.springframework.web.servlet.FrameworkServlet#configureAndRefreshWebApplicationContext,逻辑跟ContextLoader一致。

  • SpringApplication
    org.springframework.boot.SpringApplication#applyInitializers方法中通过spring.factories机制获取实例,再调用方法。

以上是关于ApplicationContextInitializer机制的主要内容,如果未能解决你的问题,请参考以下文章