源码:
initialize

// **************** org.springframework.boot.SpringApplication ******************/
private List<ApplicationContextInitializer<?>> initializers;

private void initialize(Object[] sources) {
//略...
setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class));
//略...
}
private List<ApplicationContextInitializer<?>> initializers;
public void setInitializers(
Collection<? extends ApplicationContextInitializer<?>> initializers) {
this.initializers = new ArrayList<ApplicationContextInitializer<?>>();
this.initializers.addAll(initializers);
}

(1)创建所有 classpath 下所有 “Initializer”对象


源码:

initialize

 |- getSpringFactoriesInstances



// **************** org.springframework.boot.SpringApplication ******************/
private <T> Collection<? extends T> getSpringFactoriesInstances(Class<T> type) {
return getSpringFactoriesInstances(type, new Class<?>[] {});
}
private <T> Collection<? extends T> getSpringFactoriesInstances(Class<T> type,
Class<?>[] parameterTypes, Object... args) {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
// Use names and ensure unique to protect against duplicates
Set<String> names = new LinkedHashSet<String>(
SpringFactoriesLoader.loadFactoryNames(type, classLoader));
List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
classLoader, args, names);
AnnotationAwareOrderComparator.sort(instances);
return instances;
}

(1.1)获取 classpath 下所有 “Initializer” 的全类名


源码:

initialize

 |- getSpringFactoriesInstances

     |- SpringFactoriesLoader.loadFactoryNames



​SpringFactoriesLoader.loadFactoryNames()​​ 方法在classpath下遍历 “META-INF/spring.factories” 文件,最终将这个文件中所有factoryClass指定类型的全类名解析出来,放入ArrayList中作为返回值

// **************** org.springframework.core.io.support.SpringFactoriesLoader ******************/
public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";

public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {
String factoryClassName = factoryClass.getName();
try {
Enumeration<URL> urls
= (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
List<String> result = new ArrayList<String>();
while (urls.hasMoreElements()) {
//本例中,其中一个spring.factories为:
//jar:file:/D:/../org/springframework/boot/spring-boot/1.5.9.RELEASE/
//spring-boot-1.5.9.RELEASE.jar!/META-INF/spring.factories
URL url = urls.nextElement();
// 将文件解析为Properties 类型
Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url));
// 从Properties文件中获取key为 factoryClassName 的值
String factoryClassNames = properties.getProperty(factoryClassName);
// 逗号分隔的字符串解析为String[],然后转为List放入result
result.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(factoryClassNames)));
}
return result;
}
catch (IOException ex) {
throw new IllegalArgumentException("Unable to load [" + factoryClass.getName() +
"] factories from location [" + FACTORIES_RESOURCE_LOCATION + "]", ex);
}
}

返回结果:
names = {LinkedHashSet@1647} size = 6
0 = "o.s.b.context.ConfigurationWarningsApplicationContextInitializer"
1 = "o.s.b.context.ContextIdApplicationContextInitializer"
2 = "o.s.b.context.config.DelegatingApplicationContextInitializer"
3 = "o.s.b.context.embedded.ServerPortInfoApplicationContextInitializer"
4 = "o.s.b.autoconfigure.SharedMetadataReaderFactoryContextInitializer"
5 = "o.s.b.autoconfigure.logging.AutoConfigurationReportLoggingInitializer"

🤔 Spring Boot 为什么把这些类配置在classpath下的 “META-INF/spring.factories” 文件中?

其实这是个扩展机制,用户自己可以开发一些第三方应用,在应用中创建 “META-INF/spring.factories” 文件,并在里面设置一些 Initializer ,用户在 Initializer 里实现自己的逻辑,这样在Spring Boot启动时就可以执行这些逻辑了。

(1.2)创建所有 “Initializer”实例

前面已经获取了classpath下所有的 Initializer 了,现在将其作为参数,调用 ​​createSpringFactoriesInstances(...)​​ 方法来创建这些 Initializer 的对象,并将创建好的对象放入 SpringApplication 中。


源码:

initialize

 |- getSpringFactoriesInstances

     |- createSpringFactoriesInstances



// **************** org.springframework.boot.SpringApplication ******************/
@SuppressWarnings("unchecked")
private <T> List<T> createSpringFactoriesInstances(Class<T> type,
Class<?>[] parameterTypes, ClassLoader classLoader, Object[] args,
Set<String> names) {
List<T> instances = new ArrayList<T>(names.size());
for (String name : names) {
try {
Class<?> instanceClass = ClassUtils.forName(name, classLoader);
Assert.isAssignable(type, instanceClass);
Constructor<?> constructor = instanceClass
.getDeclaredConstructor(parameterTypes);
// 通过反射实例化对象
T instance = (T) BeanUtils.instantiateClass(constructor, args);
// 通过反射实例化对象
instances.add(instance);
}
catch (Throwable ex) {
throw new IllegalArgumentException(
"Cannot instantiate " + type + " : " + name, ex);
}
}
return instances;
}

(2)设置 SpringApplication 的“Initializer”


源码:

initialize

 |- setInitializers



// **************** org.springframework.boot.SpringApplication ******************/
private List<ApplicationContextInitializer<?>> initializers;
public void setInitializers(
Collection<? extends ApplicationContextInitializer<?>> initializers) {
this.initializers = new ArrayList<ApplicationContextInitializer<?>>();
this.initializers.addAll(initializers);
}

1.2-Q1 什么是 ApplicationContextInitializer ?什么场景下使用?

1.2-Q2 设置这个initializers做什么用?

0 = "o.s.b.context.ConfigurationWarningsApplicationContextInitializer"
1 = "o.s.b.context.ContextIdApplicationContextInitializer"
2 = "o.s.b.context.config.DelegatingApplicationContextInitializer"
3 = "o.s.b.context.embedded.ServerPortInfoApplicationContextInitializer"
4 = "o.s.b.autoconfigure.SharedMetadataReaderFactoryContextInitializer"
5 = "o.s.b.autoconfigure.logging.AutoConfigurationReportLoggingInitializer"

1、搜索这个几个类,查看 ​​initialize​​​方法做了哪些事情?
2、选一个类,在其 ​​​initialize​​ 第一行打上断点,debug程序,看看方法时候调用的?