初始化器
Spring 是一個擴(kuò)展性很強(qiáng)的容器框架,為開發(fā)者提供了豐富的擴(kuò)展入口,其中一個擴(kuò)展點(diǎn)便是 ApplicationContextInitializer (應(yīng)用上下文初始化器 )。
ApplicationContextInitializer 是 Spring 在執(zhí)行 ConfigurableApplicationContext.refresh() 方法對應(yīng)用上下文進(jìn)行刷新之前調(diào)用的一個回調(diào)接口,用來完成對 Spring 應(yīng)用上下文個性化的初始化工作,該接口定義在 org.springframework.context 包中,其內(nèi)部僅包含一個 initialize() 方法,其定義代碼如下。
public interface ApplicationContextInitializer<C extends ConfigurableApplicationContext> {
/**
* Initialize the given application context.
* @param applicationContext the application to configure
*/
void initialize(C applicationContext);
}
自定義初始化器
在 Springboot 中使用自定義初始化器大致可以分為以下兩個步驟:
- 自定義初始化器,一般是實(shí)現(xiàn) ApplicationContextInitializer 接口。
- 注冊初始化器。
第一步:自定義初始化器,此處為了測試初始化器的執(zhí)行順序定義了如下3個初始化器
@Order(1)
public class Initializer1 implements ApplicationContextInitializer<ConfigurableApplicationContext> {
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
ConfigurableEnvironment environment = applicationContext.getEnvironment();
Map<String,Object> map = new HashMap<>();
map.put("key1","value1");
MapPropertySource mapPropertySource = new MapPropertySource("Initializer1", map);
environment.getPropertySources().addLast(mapPropertySource);
System.out.println("run Initializer1");
}
}
@Order(2)
public class Initializer2 implements ApplicationContextInitializer<ConfigurableApplicationContext> {
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
ConfigurableEnvironment environment = applicationContext.getEnvironment();
Map<String,Object> map = new HashMap<>();
map.put("key2","value2");
MapPropertySource mapPropertySource = new MapPropertySource("Initializer2", map);
environment.getPropertySources().addLast(mapPropertySource);
System.out.println("run Initializer2");
}
}
@Order(3)
public class Initializer3 implements ApplicationContextInitializer<ConfigurableApplicationContext> {
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
ConfigurableEnvironment environment = applicationContext.getEnvironment();
Map<String,Object> map = new HashMap<>();
map.put("key3","value3");
MapPropertySource mapPropertySource = new MapPropertySource("Initializer3", map);
environment.getPropertySources().addLast(mapPropertySource);
System.out.println("run Initializer3");
}
}
第二步:注冊初始化器,有以下三種方式
- 方式一:在啟動類中,使用 SpringApplication.addInitializers() 方法注冊。
@SpringBootApplication
@MapperScan("com.yibo.source.code.mapper")//掃描Mapper接口
public class Application {
public static void main(String[] args) {
SpringApplication springApplication = new SpringApplication(Application.class);
springApplication.addInitializers(new Initializer2());
springApplication.run();
}
}
- 方式二:在 Springboot 核心配置文件 application.properties 中增加 context.initializer.classes = [ 初始化器全類名 ] 進(jìn)行注冊。
context.initializer.classes=com.yibo.source.code.initializer.Initializer3
- 方式三:通過在CLASSPATH/META-INF/spring.factories中添加 org.springframework.context.ApplicationContextInitializer 配置項(xiàng)進(jìn)行注冊。
org.springframework.context.ApplicationContextInitializer=com.yibo.source.code.initializer.Initializer1
注意:雖然可以使用 @Order 注解來控制多個初始化器的執(zhí)行順序(數(shù)值越小越先執(zhí)行),但是,通過不同方式注冊的初始化器的執(zhí)行順序也有所不同,若多個初始化器注冊的方式不同會導(dǎo)致 @Order 注解順序無效,從以上程序執(zhí)行后的打印結(jié)果來看,三種方式注冊的初始化器的執(zhí)行順序依次是:方式二 --> 方式一 --> 方式三。
Springboot定義的初始化器
Springboot定義的 ApplicationContextInitializer 接口的實(shí)現(xiàn)類有下面幾個,如圖所示。

DelegatingApplicationContextInitializer
DelegatingApplicationContextInitializer 初始化器負(fù)責(zé)讀取核心配置文件 context.initializer.classes 配置項(xiàng)指定的初始化器,并調(diào)用它們的 initialize() 方法來完成對應(yīng)用上下文的初始化工作。
public class DelegatingApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext>, Ordered {
private static final String PROPERTY_NAME = "context.initializer.classes";
private int order = 0;
public DelegatingApplicationContextInitializer() {
}
/**
* 對應(yīng)用上下文進(jìn)行初始化
*/
public void initialize(ConfigurableApplicationContext context) {
// 獲取核心配置文件中指定的初始化器類
ConfigurableEnvironment environment = context.getEnvironment();
List<Class<?>> initializerClasses = this.getInitializerClasses(environment);
if (!initializerClasses.isEmpty()) {
// 利用獲取到的初始化器類對應(yīng)用上下文進(jìn)行初始化
this.applyInitializerClasses(context, initializerClasses);
}
}
/**
* 讀取核心配置文件中 context.initializer.classes 指定的初始化器類
*/
private List<Class<?>> getInitializerClasses(ConfigurableEnvironment env) {
String classNames = env.getProperty("context.initializer.classes");
List<Class<?>> classes = new ArrayList();
if (StringUtils.hasLength(classNames)) {
String[] var4 = StringUtils.tokenizeToStringArray(classNames, ",");
int var5 = var4.length;
for(int var6 = 0; var6 < var5; ++var6) {
String className = var4[var6];
classes.add(this.getInitializerClass(className));
}
}
return classes;
}
/**
* 使用指定的初始化器類對應(yīng)用上下文進(jìn)行初始化
*/
private void applyInitializerClasses(ConfigurableApplicationContext context, List<Class<?>> initializerClasses) {
Class<?> contextClass = context.getClass();
List<ApplicationContextInitializer<?>> initializers = new ArrayList();
Iterator var5 = initializerClasses.iterator();
while(var5.hasNext()) {
Class<?> initializerClass = (Class)var5.next();
initializers.add(this.instantiateInitializer(contextClass, initializerClass));
}
this.applyInitializers(context, initializers);
}
/**
* 使用指定的初始化器對應(yīng)用上下文進(jìn)行初始化
*/
private void applyInitializers(ConfigurableApplicationContext context, List<ApplicationContextInitializer<?>> initializers) {
// 對初始化器進(jìn)行 Order 排序
initializers.sort(new AnnotationAwareOrderComparator());
Iterator var3 = initializers.iterator();
while(var3.hasNext()) {
ApplicationContextInitializer initializer = (ApplicationContextInitializer)var3.next();
initializer.initialize(context);
}
}
......
}
ContextIdApplicationContextInitializer
ContextIdApplicationContextInitializer 初始化器的作用是給應(yīng)用上下文設(shè)置一個ID
這個ID通過environment中的"spring.application.name"獲取,如果不存在則直接返回默認(rèn)"application"
public class ContextIdApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext>, Ordered {
private int order = 2147483637;
public ContextIdApplicationContextInitializer() {
}
public void setOrder(int order) {
this.order = order;
}
public int getOrder() {
return this.order;
}
public void initialize(ConfigurableApplicationContext applicationContext) {
ContextIdApplicationContextInitializer.ContextId contextId = this.getContextId(applicationContext);
applicationContext.setId(contextId.getId());
applicationContext.getBeanFactory().registerSingleton(ContextIdApplicationContextInitializer.ContextId.class.getName(), contextId);
}
private String getApplicationId(ConfigurableEnvironment environment) {
String name = environment.getProperty("spring.application.name");
return StringUtils.hasText(name) ? name : "application";
}
}
ConfigurationWarningsApplicationContextInitializer
ConfigurationWarningsApplicationContextInitializer 初始化器用來對常見的由于配置錯誤而引起的警告進(jìn)行打印報告。
public class ConfigurationWarningsApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
private static final Log logger = LogFactory.getLog(ConfigurationWarningsApplicationContextInitializer.class);
public void initialize(ConfigurableApplicationContext context) {
// 添加一個 ConfigurationWarningsPostProcessor 用來打印警告信息
context.addBeanFactoryPostProcessor(new ConfigurationWarningsApplicationContextInitializer.ConfigurationWarningsPostProcessor(this.getChecks()));
}
}
其中的 ConfigurationWarningsPostProcessor 是一個靜態(tài)內(nèi)部類,用來打印注冊 BeanDefinition 過程中產(chǎn)生的配置錯誤警告信息。
protected static final class ConfigurationWarningsPostProcessor implements PriorityOrdered, BeanDefinitionRegistryPostProcessor {
private ConfigurationWarningsApplicationContextInitializer.Check[] checks;
public ConfigurationWarningsPostProcessor(ConfigurationWarningsApplicationContextInitializer.Check[] checks) {
this.checks = checks;
}
public int getOrder() {
return 2147483646;
}
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
}
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
ConfigurationWarningsApplicationContextInitializer.Check[] var2 = this.checks;
int var3 = var2.length;
for(int var4 = 0; var4 < var3; ++var4) {
ConfigurationWarningsApplicationContextInitializer.Check check = var2[var4];
String message = check.getWarning(registry);
if (StringUtils.hasLength(message)) {
this.warn(message);
}
}
}
private void warn(String message) {
if (ConfigurationWarningsApplicationContextInitializer.logger.isWarnEnabled()) {
ConfigurationWarningsApplicationContextInitializer.logger.warn(String.format("%n%n** WARNING ** : %s%n%n", message));
}
}
}
ServerPortInfoApplicationContextInitializer
ServerPortInfoApplicationContextInitializer 初始化器通過監(jiān)聽 EmbeddedServletContainerInitializedEvent 事件,來對內(nèi)部服務(wù)器實(shí)際要監(jiān)聽的端口號進(jìn)行屬性設(shè)置。
public class ServerPortInfoApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext>, ApplicationListener<WebServerInitializedEvent> {
public ServerPortInfoApplicationContextInitializer() {
}
public void initialize(ConfigurableApplicationContext applicationContext) {
applicationContext.addApplicationListener(this);
}
public void onApplicationEvent(WebServerInitializedEvent event) {
String propertyName = "local." + this.getName(event.getApplicationContext()) + ".port";
this.setPortProperty((ApplicationContext)event.getApplicationContext(), propertyName, event.getWebServer().getPort());
}
private String getName(WebServerApplicationContext context) {
String name = context.getServerNamespace();
return StringUtils.hasText(name) ? name : "server";
}
private void setPortProperty(ApplicationContext context, String propertyName, int port) {
if (context instanceof ConfigurableApplicationContext) {
this.setPortProperty(((ConfigurableApplicationContext)context).getEnvironment(), propertyName, port);
}
if (context.getParent() != null) {
this.setPortProperty(context.getParent(), propertyName, port);
}
}
private void setPortProperty(ConfigurableEnvironment environment, String propertyName, int port) {
MutablePropertySources sources = environment.getPropertySources();
PropertySource<?> source = sources.get("server.ports");
if (source == null) {
source = new MapPropertySource("server.ports", new HashMap());
sources.addFirst((PropertySource)source);
}
((Map)((PropertySource)source).getSource()).put(propertyName, port);
}
}
SharedMetadataReaderFactoryContextInitializer
SharedMetadataReaderFactoryContextInitializer 初始化器用來創(chuàng)建一個可以在 ConfigurationClassPostProcessor 和Spring Boot 之間共享的CachingMetadataReaderFactory。
class SharedMetadataReaderFactoryContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext>, Ordered {
public static final String BEAN_NAME = "org.springframework.boot.autoconfigure.internalCachingMetadataReaderFactory";
SharedMetadataReaderFactoryContextInitializer() {
}
public void initialize(ConfigurableApplicationContext applicationContext) {
applicationContext.addBeanFactoryPostProcessor(new SharedMetadataReaderFactoryContextInitializer.CachingMetadataReaderFactoryPostProcessor());
}
}
看下SpringBoot是如何加載初始化器的
入口類
@SpringBootApplication
@MapperScan("com.yibo.source.code.mapper")//掃描Mapper接口
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class,args);
}
}
@SpringBootApplication我們上一篇文章http://www.itdecent.cn/p/ba68748f8113
中大概的講過了,有興趣的可以看看我第一篇關(guān)于SpringBoot的文章,本篇文章主要關(guān)注SpringApplication.run(Application.class, args);,我們跟進(jìn)去看看
// 調(diào)用靜態(tài)類,參數(shù)對應(yīng)的就是HelloWorldMainApplication.class以及main方法中的args
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
return run(new Class[]{primarySource}, args);
}
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
return (new SpringApplication(primarySources)).run(args);
}
它實(shí)際上會構(gòu)造一個SpringApplication的實(shí)例,并把我們的啟動類Application.class作為參數(shù)傳進(jìn)去,然后運(yùn)行它的run方法
SpringApplication構(gòu)造器
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.sources = new LinkedHashSet();
this.bannerMode = Mode.CONSOLE;
this.logStartupInfo = true;
this.addCommandLineProperties = true;
this.addConversionService = true;
this.headless = true;
this.registerShutdownHook = true;
this.additionalProfiles = new HashSet();
this.isCustomEnvironment = false;
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
//把Application.class設(shè)置為屬性存儲起來
this.primarySources = new LinkedHashSet(Arrays.asList(primarySources));
//設(shè)置應(yīng)用類型是Standard還是Web
this.webApplicationType = WebApplicationType.deduceFromClasspath();
//設(shè)置初始化器(Initializer),最后會調(diào)用這些初始化器
this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
//設(shè)置監(jiān)聽器(Listener)
this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = this.deduceMainApplicationClass();
}
設(shè)置應(yīng)用類型
public enum WebApplicationType {
NONE,
SERVLET,
REACTIVE;
private static final String[] SERVLET_INDICATOR_CLASSES = new String[]{"javax.servlet.Servlet", "org.springframework.web.context.ConfigurableWebApplicationContext"};
private static final String WEBMVC_INDICATOR_CLASS = "org.springframework.web.servlet.DispatcherServlet";
private static final String WEBFLUX_INDICATOR_CLASS = "org.springframework.web.reactive.DispatcherHandler";
private static final String JERSEY_INDICATOR_CLASS = "org.glassfish.jersey.servlet.ServletContainer";
private static final String SERVLET_APPLICATION_CONTEXT_CLASS = "org.springframework.web.context.WebApplicationContext";
private static final String REACTIVE_APPLICATION_CONTEXT_CLASS = "org.springframework.boot.web.reactive.context.ReactiveWebApplicationContext";
private WebApplicationType() {
}
static WebApplicationType deduceFromClasspath() {
if (ClassUtils.isPresent("org.springframework.web.reactive.DispatcherHandler", (ClassLoader)null) && !ClassUtils.isPresent("org.springframework.web.servlet.DispatcherServlet", (ClassLoader)null) && !ClassUtils.isPresent("org.glassfish.jersey.servlet.ServletContainer", (ClassLoader)null)) {
return REACTIVE;
} else {
String[] var0 = SERVLET_INDICATOR_CLASSES;
int var1 = var0.length;
for(int var2 = 0; var2 < var1; ++var2) {
String className = var0[var2];
if (!ClassUtils.isPresent(className, (ClassLoader)null)) {
return NONE;
}
}
return SERVLET;
}
}
}
這里主要是通過類加載器判斷REACTIVE相關(guān)的Class是否存在,如果不存在,則web環(huán)境即為SERVLET類型。這里設(shè)置好web環(huán)境類型,在后面會根據(jù)類型初始化對應(yīng)環(huán)境。大家還記得我們第一篇文章中引入的依賴嗎?
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
spring-boot-starter-web 的pom又會引入Tomcat和spring-webmvc,如下
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>2.1.10.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-json</artifactId>
<version>2.1.10.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<version>2.1.10.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.0.18.Final</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.1.11.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.1.11.RELEASE</version>
<scope>compile</scope>
</dependency>
</dependencies>

很明顯spring-webmvc中存在DispatcherServlet這個類,也就是我們以前SpringMvc的核心Servlet,通過類加載能加載DispatcherServlet這個類,那么我們的應(yīng)用類型自然就是WebApplicationType.SERVLET
設(shè)置初始化器(Initializer)
this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
我們先來看看this.getSpringFactoriesInstances(ApplicationContextInitializer.class)
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
return this.getSpringFactoriesInstances(type, new Class[0]);
}
// 這里的入?yún)ype就是ApplicationContextInitializer.class
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
ClassLoader classLoader = this.getClassLoader();
// 使用Set保存names來避免重復(fù)元素
Set<String> names = new LinkedHashSet(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
// 根據(jù)names來進(jìn)行實(shí)例化
List<T> instances = this.createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
// 對實(shí)例進(jìn)行排序
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
這里面首先會根據(jù)入?yún)ype讀取所有的names(是一個String集合),然后根據(jù)這個集合來完成對應(yīng)的實(shí)例化操作:
public final class SpringFactoriesLoader {
public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
// 入?yún)⒕褪茿pplicationContextInitializer.class
public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) {
String factoryClassName = factoryClass.getName();
return (List)loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
}
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
MultiValueMap<String, String> result = (MultiValueMap)cache.get(classLoader);
if (result != null) {
return result;
} else {
try {
//從類路徑的META-INF/spring.factories中加載所有默認(rèn)的自動配置類
Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
LinkedMultiValueMap result = new LinkedMultiValueMap();
while(urls.hasMoreElements()) {
URL url = (URL)urls.nextElement();
UrlResource resource = new UrlResource(url);
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
Iterator var6 = properties.entrySet().iterator();
while(var6.hasNext()) {
Entry<?, ?> entry = (Entry)var6.next();
//獲取ApplicationContextInitializer.class的所有值
String factoryClassName = ((String)entry.getKey()).trim();
String[] var9 = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());
int var10 = var9.length;
for(int var11 = 0; var11 < var10; ++var11) {
String factoryName = var9[var11];
result.add(factoryClassName, factoryName.trim());
}
}
}
cache.put(classLoader, result);
return result;
} catch (IOException var13) {
throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var13);
}
}
}
}
這個方法會嘗試從類路徑的META-INF/spring.factories處讀取相應(yīng)配置文件,然后進(jìn)行遍歷,讀取配置文件中Key為:org.springframework.context.ApplicationContextInitializer的value。以spring-boot-autoconfigure這個包為例,它的META-INF/spring.factories部分定義如下所示:

# Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\
org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener
這兩個類名會被讀取出來,然后放入到Set<String>集合中,準(zhǔn)備開始下面的實(shí)例化操作:
// parameterTypes: 上一步得到的names集合
private <T> List<T> createSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, ClassLoader classLoader, Object[] args, Set<String> names) {
List<T> instances = new ArrayList(names.size());
Iterator var7 = names.iterator();
while(var7.hasNext()) {
String name = (String)var7.next();
try {
Class<?> instanceClass = ClassUtils.forName(name, classLoader);
//確認(rèn)被加載類是ApplicationContextInitializer的子類
Assert.isAssignable(type, instanceClass);
Constructor<?> constructor = instanceClass.getDeclaredConstructor(parameterTypes);
//反射實(shí)例化對象
T instance = BeanUtils.instantiateClass(constructor, args);
//加入List集合中
instances.add(instance);
} catch (Throwable var12) {
throw new IllegalArgumentException("Cannot instantiate " + type + " : " + name, var12);
}
}
return instances;
}
確認(rèn)被加載的類確實(shí)是org.springframework.context.ApplicationContextInitializer的子類,然后就是得到構(gòu)造器進(jìn)行初始化,最后放入到實(shí)例列表中。
因此,所謂的初始化器就是org.springframework.context.ApplicationContextInitializer的實(shí)現(xiàn)類,這個接口是這樣定義的:
public interface ApplicationContextInitializer<C extends ConfigurableApplicationContext> {
/**
* Initialize the given application context.
* @param applicationContext the application to configure
*/
void initialize(C applicationContext);
}
在Spring上下文被刷新之前進(jìn)行初始化的操作。即在SpringApplication.prepareContext方法中調(diào)用applyInitializers方法進(jìn)行初始化操作,典型地比如在Web應(yīng)用中,注冊Property Sources或者是激活Profiles。Property Sources比較好理解,就是配置文件。Profiles是Spring為了在不同環(huán)境下(如DEV,TEST,PRODUCTION等),加載不同的配置項(xiàng)而抽象出來的一個實(shí)體。
public class SpringApplication {
public ConfigurableApplicationContext run(String... args) {
......
this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
......
}
private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
......
this.applyInitializers(context);
......
}
}
SpringFactoriesLoader介紹
- 1、框架內(nèi)部使用的通用工廠加載機(jī)制
- 2、從classpath下多個jar包特定的位置讀取文件并初始化類
- 3、文件內(nèi)容必須是kv形式,即properties類型
- 4、key是全限定名,value是實(shí)現(xiàn),多個實(shí)現(xiàn)用逗號分隔
SpringFactoriesLoader的作用
SpringBoot框架中從類路徑j(luò)ar包中讀取特定文件實(shí)現(xiàn)擴(kuò)展類的載入


系統(tǒng)初始化器調(diào)用流程

文章開始的三種自定義初始化器實(shí)現(xiàn)原理
- 定義在spring.factories文件中被SpringFactoriesLoader發(fā)現(xiàn)注冊
- SpringApplication初始化完畢后手動添加
- 定義成環(huán)境變量被DelegatingApplicationContextInitializer發(fā)現(xiàn)注冊
推薦使用在spring.factories文件中定義系統(tǒng)初始化器被SpringFactoriesLoader發(fā)現(xiàn)注冊的方式
在spring.factories文件中定義系統(tǒng)初始化器,被SpringFactoriesLoader載入,成為SpringBoot框架的SpringApplicationInitializer屬性,在運(yùn)行的時候會遍歷這個屬性依次調(diào)用initialize方法完成向容器內(nèi)注冊屬性。

參考:
https://blog.csdn.net/pengjunlee/article/details/79394735