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