Springboot中 加载初始化器的三种方式 ApplicationContextInitializer



ApplicationContextInitializer主要用于初始化 spring上下文 ConfigurableApplicationContext.
所有的初始化器将在spring创建完ConfigurableApplicationContext之后紧接着执行.并且在ConfigurableApplicationContext#refresh()方法之前.

通常用于配置环境 ConfigurableApplicationContext#getEnvironment(), 或者注册各种前置处理器context.addBeanFactoryPostProcessor()等. 

 

/**
 * 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
 * @param <C> the application context type
 * @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);

}

 

下面是注册初始化器的三种方式:

 

1.通过在项目中建立 META-INF/spring.factories 文件 并在文件中添加类信息:

# Application Context Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\
org.springframework.boot.context.ContextIdApplicationContextInitializer,\
org.springframework.boot.context.config.DelegatingApplicationContextInitializer,\
org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializer

ps: springboot在启动的时候会自动全项目(包括引入的所有jar包)扫描 META-INF目录下的spring.factories文件, 然后一次性全部读取到 缓存中 ,根据ClassLoader,进行区分不同缓存. 然后会执行无参构造函数进行实例化, 排序 存储在org.springframework.boot.SpringApplication#initializers变量中.

     * The location to look for factories.
     * <p>Can be present in multiple JAR files.
     */
    public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
  // 缓存
private static final Map<ClassLoader, MultiValueMap<String, String>> cache = new ConcurrentReferenceHashMap<>(); private SpringFactoriesLoader() { }
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
MultiValueMap<String, String> result = cache.get(classLoader); // 不同classLoader对应不同的缓存
if (result != null) {
return result;
}
try {
Enumeration<URL> urls = (classLoader != null ?
classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
result = new LinkedMultiValueMap<>();//多值Map key对应要加载的classType,value为List列表,存储spring.factories中classType对应的具体class全限定名
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
UrlResource resource = new UrlResource(url);
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
for (Map.Entry<?, ?> entry : properties.entrySet()) {
String factoryTypeName = ((String) entry.getKey()).trim();
for (String factoryImplementationName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
result.add(factoryTypeName, factoryImplementationName.trim());
}
}
}
cache.put(classLoader, result);
return result;
}
catch (IOException ex) {
throw new IllegalArgumentException("Unable to load factories from location [" +
FACTORIES_RESOURCE_LOCATION + "]", ex);
}
}
 

2.在执行SpringApplication run方法之前进行自定义添加到SpringApplication#initializers

public static void main(String[] args) {
        SpringApplication springApplication = new SpringApplication(SampleActiveMQApplication.class);     
        springApplication.addInitializers(new MyApplicationContextInitializer); //手动添加       
     springApplication.run(args);
}

3.在配置文件中配置

context.initializer.classes = MyApplicationContextInitializer1,MyApplicationContextInitializer2,MyApplicationContextInitializer3 //注意替换为全限定名 并用逗号隔开

ps:

在springboot自带的包中,有一个自带的 委托初始化器DelegatingApplicationContextInitializer,因为他的本身的Order是最靠前的,所以在执行所有的初始化器的时候会首先执行这个.

 

 

 

 由上图可知 在加载并实例化完所有的配置的类后,首先进行了排序,并接着就遍历执行了initialize(context)方法,也就是说在配置文件中配置的话 会优先于其他的配置方式执行.

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM