初始化SpringApplication
SpringBoot通过执行
@SpringBootApplication
标记类的main函数中的
SpringApplication.run(SpringBootTestApplication.class, args)
进行启动
@SpringBootApplication
public class SpringBootTestApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootTestApplication.class, args);
}
}
其实是执行了SpringApplication类中的run方法,可以看到,SpringBoot启动分为两步,第一步是实例化SpringApplication,再对实例化的SpringApplication对象执行run。
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);
}
SpringApplication的构造方法主要是为了初始化SpringApplication的一些基础属性,例如主启动类、web应用类型、启动载入器、初始化器列表、监听器列表等。
public SpringApplication(Class<?>... primarySources) {
this(null, primarySources);
}
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
// 初始化resourceLoader,此时resourceLoader为null
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
// 将主启动类Class装入到该primarySources中
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
// 获取到此次应用类型为Servlet
this.webApplicationType = WebApplicationType.deduceFromClasspath();
// 初始化启动载入器,通过getSpringFactoriesInstances获取所有的启动载入器实例,此处获取到的载入器为空列表
this.bootstrappers = new ArrayList<>(getSpringFactoriesInstances(Bootstrapper.class));
// 设置上下文初始化器列表,用于后续在准备应用上下文时,在生成上下文后对上下文进行一些初始化
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
// 设置监听器列表,用于在启动时发布各种事件通知(springboot启动运用了许多的监听者模式)
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
// 获取到主启动类实例
this.mainApplicationClass = deduceMainApplicationClass();
}
初始化完成后,各个属性的值如下:
this.bootstrappers:
空列表
this.initializers:共7个
DelegatingApplicationContextInitializer
SharedMetadataReaderFactoryContextInitializer
ContextIdApplicationContextInitializer
ConfigurationWarningsApplicationContextInitializer
RSocketPortInfoApplicationContextInitializer
ServerPortInfoApplicationContextInitializer
ConditionEvaluationReportLoggingListener
this.listeners:共9个
EnvironmentPostProcessorApplicationListener
AnsiOutputApplicationListener
LoggingApplicationListener
BackgroundPreinitializer
DelegatingApplicationListener
ParentContextCloserApplicationListener
ClearCachesApplicationListener
FileEncodingApplicationListener
LiquibaseServiceLocatorApplicationListener
getSpringFactoriesInstances:
可以看到,在初始化启动载入器、初始化器、监听器时,均是调用
getSpringFactoriesInstances
方法,通过传入不同的Class类型获取到不同的实例,此处对getSpringFactoriesInstances方法进行解析
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
return getSpringFactoriesInstances(type, new Class<?>[] {});
}
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
// 由于this.resourceLoader为null,故此处返回的ClassUtils.getDefaultClassLoader()
ClassLoader classLoader = getClassLoader();
// 从此处获取到满足类型的所有类名称列表
Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
// 用类名称列表,通过反射机制对它们进行实例化
List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
// 对实例进行排序
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
可以看到,获取满足类型的类名称时,调用了
SpringFactoriesLoader.loadFactoryNames(type, classLoader)
方法,此处对SpringFactoriesLoader.loadFactoryNames(type, classLoader)方法进行解析:
其中的类名配置在META-INF/spring.factories文件中,springboot会扫描路径下的所有该名称文件,并通过键值对进行匹配,纯净的springboot中,META-INF/spring.factories 在包 org.springframework.boot:spring-boot 和 org.springframework.boot:spring-boot-autoconfigure中
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
ClassLoader classLoaderToUse = classLoader;
if (classLoaderToUse == null) {
classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();
}
// 获取到class类型的名称
String factoryTypeName = factoryType.getName();
return loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList());
}
public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories"
private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {
// 首先尝试从缓存中获取map
Map<String, List<String>> result = cache.get(classLoader);
if (result != null) {
return result;
}
// 如果缓存中没获取到,加载资源文件META-INF/spring.factories,从中根据不同类型获取到不同的类名称,并将它们放入到缓存中
// 在最原始的springboot启动时,只有在org.springframework.boot和org.springframework.boot-autoconfigure两个jar包下存在META-INF/spring.factories文件
// spring.factories文件中是以key=value形式储存,多个value之间用逗号分隔
result = new HashMap<>();
try {
Enumeration<URL> urls = classLoader.getResources(FACTORIES_RESOURCE_LOCATION);
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();
String[] factoryImplementationNames =
StringUtils.commaDelimitedListToStringArray((String) entry.getValue());
for (String factoryImplementationName : factoryImplementationNames) {
result.computeIfAbsent(factoryTypeName, key -> new ArrayList<>())
.add(factoryImplementationName.trim());
}
}
}
// Replace all lists with unmodifiable lists containing unique elements
result.replaceAll((factoryType, implementations) -> implementations.stream().distinct()
.collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList)));
cache.put(classLoader, result);
}
catch (IOException ex) {
throw new IllegalArgumentException("Unable to load factories from location [" +
FACTORIES_RESOURCE_LOCATION + "]", ex);
}
return result;
}