SpringBoot启动分析1:SpringApplication的初始化
前言:本次源码分析使用SpringBoot-2.2.5.RELEASE版本。
1.1 Initializer初始化器
1.1.1 Initializer概述
初始化器的基类ApplicationContextInitializer是这么描述初始化器的:
在Spring的上下文环境对象调用refresh()方法之前调用的回调接口,这些初始化器通常被用于web应用需要初始化应用上下文。
实际上,ApplicationContextInitializer只提供了一个接口,接口定义如下:
public interface ApplicationContextInitializer<C extends ConfigurableApplicationContext> {
void initialize(C applicationContext);
}
所以看出在上下文环境对象调用refresh()方法之前调用的回调接口就是各个实现了ApplicationContextInitializer实现类的initialize方法。
1.1.2 Initializer实现方式
基于SpringBoot的SPI
如果查看过SpringBoot的启动源码那么会很清楚这种方式的实现方式,实际上它是通过SpringFactoriesLoader读取spring.factories配置文件中的实现来实例化Initializer,
最后在必要的情况下调用这些Initializer的initialize方法。
首先,创建一个Initializer实现:
@Order(1)
public class Order1Initializer implements ApplicationContextInitializer {
private Logger log = LoggerFactory.getLogger(getClass());
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
log.info("order1Initializer...");
}
}
其次,在resources目录中新增META-INF目录并在该目录中添加spring.factories配置文件并添加以下配置:
org.springframework.context.ApplicationContextInitializer=com.neckel.springboot.initializer.Order1Initializer
最后启动SpringBoot:
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
查看控制台的日志输出情况:
2020-08-03 16:15:20.283 INFO 16108 --- [ main] c.n.s.initializer.Order1Initializer : order1Initializer...
2020-08-03 16:15:20.291 INFO 16108 --- [ main] com.neckel.springboot.Application : Starting Application on PC-27 with PID 16108 (C:\Users\Administrator\IdeaProjects\neckel-springboot\target\classes started by Administrator in C:\Users\Administrator\IdeaProjects\neckel-springboot)
2020-08-03 16:15:20.292 INFO 16108 --- [ main] com.neckel.springboot.Application : No active profile set, falling back to default profiles: default
2020-08-03 16:15:20.794 INFO 16108 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
......
基于启动类设置
基于SpringBoot的SPI的方式,最终是将从spring.factories配置文件读取到的实现添加到SpringApplication中的initializers属性中,所以使用我们完全可以等SpringApplication初始化完成之后,收到将Initializer设置到initializers属性中。
首先,创建一个Initializer实现:
@Order(2)
public class Order2Initializer implements ApplicationContextInitializer {
private Logger log = LoggerFactory.getLogger(getClass());
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
log.info("order2Initializer...");
}
}
其次,在启动类中将该初始化器添加到SpringApplication中:
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication springApplication = new SpringApplication(Application.class);
springApplication.addInitializers(new Order1Initializer());
springApplication.run(args);
}
}
最后启动SpringBoot,查看控制台的日志输出情况:
2020-08-03 16:43:42.656 INFO 18272 --- [ main] c.n.s.initializer.Order1Initializer : order1Initializer...
2020-08-03 16:43:42.659 INFO 18272 --- [ main] c.n.s.initializer.Order2Initializer : order2Initializer...
2020-08-03 16:43:42.665 INFO 18272 --- [ main] com.neckel.springboot.Application : Starting Application on PC-27 with PID 18272 (C:\Users\Administrator\IdeaProjects\neckel-springboot\target\classes started by Administrator in C:\Users\Administrator\IdeaProjects\neckel-springboot)
2020-08-03 16:43:42.665 INFO 18272 --- [ main] com.neckel.springboot.Application : No active profile set, falling back to default profiles: default
2020-08-03 16:43:43.188 INFO 18272 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
......
基于配置文件配置
初始化器的基类ApplicationContextInitializer有个实现类DelegatingApplicationContextInitializer,它用于读取配置文件中的context.initializer.classes来设置初始化器。
首先,创建一个Initializer实现:
@Order(3)
public class Order3Initializer implements ApplicationContextInitializer {
private Logger log = LoggerFactory.getLogger(getClass());
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
log.info("order3Initializer...");
}
}
其次,在全局配置文件中添加以下配置:
context.initializer.classes=com.neckel.springboot.initializer.Order3Initializer
最后启动SpringBoot,查看控制台的日志输出情况:
2020-08-03 16:49:31.959 INFO 9756 --- [ main] c.n.s.initializer.Order3Initializer : order3Initializer...
2020-08-03 16:49:31.960 INFO 9756 --- [ main] c.n.s.initializer.Order1Initializer : order1Initializer...
2020-08-03 16:49:31.960 INFO 9756 --- [ main] c.n.s.initializer.Order2Initializer : order2Initializer...
2020-08-03 16:49:31.966 INFO 9756 --- [ main] com.neckel.springboot.Application : Starting Application on PC-27 with PID 9756 (C:\Users\Administrator\IdeaProjects\neckel-springboot\target\classes started by Administrator in C:\Users\Administrator\IdeaProjects\neckel-springboot)
2020-08-03 16:49:31.966 INFO 9756 --- [ main] com.neckel.springboot.Application : No active profile set, falling back to default profiles: default
2020-08-03 16:49:32.445 INFO 9756 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
......
1.1.3 可能存在的疑问
在上方的三个Initializer初始化器中,它们都添加了@Order注解,该注解用于对它们进行排序,最终根据排序的顺序执行它们各自的initialize方法。至于如何排序后续会说明,但是这里存在疑问是Order3Initializer中的@Order(3)设置的优先级比其它两个初始化器还低,为什么还优先执行?答案在于Order3Initializer是通过全局配置文件配置被加载到SpringApplication中,它是由DelegatingApplicationContextInitializer读取全局配置文件中的context.initializer.classes属性配置,并且在DelegatingApplicationContextInitializer源码中可以看到它为读取到的初始化器设置了默认的优先级:
public class DelegatingApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext>, Ordered {
private static final String PROPERTY_NAME = "context.initializer.classes";
// 该优先级已超越了Order1Initializer和Order2Initializer的优先级
private int order = 0;
......
}
1.2 Listener监听器
1.2.1 Listener概述
这里的Listener指的是ApplicationListener类型的监听器,它是应用事件监听接口,是继承自Java标准观察者模式的EventListener接口。从Spring3.0之后,一个ApplicationListener实现可以声明自己所关心的事件类型。当一个ApplicationListener被注册到Spring ApplicationContext之后,应用运行时应用事件会陆续发生,对应响应类型的事件监听器会被调用。
以下是EventListener接口和ApplicationListener接口的接口定义:
# EventListener接口是JDK1.1提供的标准接口,所有的事件监听者都要实现这个接口
public interface EventListener {}
# ApplicationListener接口,继承自EventListener接口
@FunctionalInterface
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
void onApplicationEvent(E event);
}
在ApplicationListener接口中可以看到它处理的事件类型是ApplicationEvent,该事件抽象类是所有事件的基类,若要自定义事件则需要继承该事件基类,当自定义监听器触发监听后会调用自己的onApplicationEvent方法处理自定义的事件。
1.2.2 Listener实现方式
基于SpringBoot的SPI
这种实现方式和Initializer初始化器一样,都是通过SpringFactoriesLoader读取spring.factories配置文件中的实现来实例化Listener。
首先,创建一个Listener实现:
@Order(1)
public class Order1Listener implements ApplicationListener<ApplicationStartedEvent> {
private Logger log = LoggerFactory.getLogger(getClass());
public void onApplicationEvent(ApplicationStartedEvent event) {
log.info("order1Listener...");
}
}
其次,在resources目录中新增META-INF目录并在该目录中添加spring.factories配置文件并添加以下配置:
org.springframework.context.ApplicationListener=com.neckel.springboot.listener.Order1Listener
最后启动SpringBoot:
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
查看控制台的日志输出情况:
......
2020-08-06 23:33:57.499 INFO 8908 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.31]
2020-08-06 23:33:57.586 INFO 8908 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2020-08-06 23:33:57.586 INFO 8908 --- [ main] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 1500 ms
2020-08-06 23:33:57.752 INFO 8908 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'
2020-08-06 23:33:57.897 INFO 8908 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
2020-08-06 23:33:57.900 INFO 8908 --- [ main] com.neckel.source.Application : Started Application in 2.232 seconds (JVM running for 2.639)
2020-08-06 23:33:57.900 INFO 8908 --- [ main] c.neckel.source.listener.Order1Listener : order1Listener...
基于启动类设置
基于SpringBoot的SPI的方式,最终是将从spring.factories配置文件读取到的实现添加到SpringApplication中的listeners属性中,所以我们完全可以跟Initializer一样等SpringApplication初始化完成之后,收到将Listener设置到listeners属性中。
首先,创建一个Listener实现:
@Order(2)
public class Order2Listener implements ApplicationListener<ApplicationStartedEvent> {
private Logger log = LoggerFactory.getLogger(getClass());
public void onApplicationEvent(ApplicationStartedEvent event) {
log.info("order2Listener...");
}
}
其次,在启动类中将该监听器添加到SpringApplication中:
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication springApplication = new SpringApplication(Application.class);
springApplication.addListeners(new Order2Listener());
springApplication.run(args);
}
}
最后启动SpringBoot,查看控制台的日志输出情况:
2020-08-06 23:37:27.943 INFO 9132 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.31]
2020-08-06 23:37:28.028 INFO 9132 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2020-08-06 23:37:28.029 INFO 9132 --- [ main] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 1353 ms
2020-08-06 23:37:28.218 INFO 9132 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'
2020-08-06 23:37:28.360 INFO 9132 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
2020-08-06 23:37:28.362 INFO 9132 --- [ main] com.neckel.source.Application : Started Application in 2.248 seconds (JVM running for 2.693)
2020-08-06 23:37:28.363 INFO 9132 --- [ main] c.neckel.source.listener.Order1Listener : order1Listener...
2020-08-06 23:37:28.363 INFO 9132 --- [ main] c.neckel.source.listener.Order2Listener : order2Listener...
基于配置文件配置
监听器的基类ApplicationListener有个实现类DelegatingApplicationListener,它用于读取配置文件中的context.listener.classes来设置监听器。
首先,创建一个Listener实现:
@Order(3)
public class Order3Listener implements ApplicationListener<ApplicationStartedEvent> {
private Logger log = LoggerFactory.getLogger(getClass());
public void onApplicationEvent(ApplicationStartedEvent event) {
log.info("order3Listener...");
}
}
其次,在全局配置文件中添加以下配置:
context.listener.classes=com.neckel.springboot.listener.Order3Listener
最后启动SpringBoot,查看控制台的日志输出情况:
2020-08-06 23:45:07.795 INFO 2500 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.31]
2020-08-06 23:45:07.878 INFO 2500 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2020-08-06 23:45:07.878 INFO 2500 --- [ main] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 1397 ms
2020-08-06 23:45:08.018 INFO 2500 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'
2020-08-06 23:45:08.151 INFO 2500 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
2020-08-06 23:45:08.153 INFO 2500 --- [ main] com.neckel.source.Application : Started Application in 2.125 seconds (JVM running for 2.539)
2020-08-06 23:45:08.154 INFO 2500 --- [ main] c.neckel.source.listener.Order3Listener : order3Listener...
2020-08-06 23:45:08.154 INFO 2500 --- [ main] c.neckel.source.listener.Order1Listener : order1Listener...
2020-08-06 23:45:08.154 INFO 2500 --- [ main] c.neckel.source.listener.Order2Listener : order2Listener...
跟Initializer初始化器一样三个Listener都添加了@Order注解,其中order3Listener优先被执行是因为order3Listener是通过全局配置文件配置被加载到SpringApplication中,它是由DelegatingApplicationListener读取全局配置文件中的context.listener.classes属性配置,并且在DelegatingApplicationListener源码中可以看到它为读取到的初始化器设置了默认的优先级:
public class DelegatingApplicationListener implements ApplicationListener<ApplicationEvent>, Ordered {
private static final String PROPERTY_NAME = "context.listener.classes";
private int order = 0;
......
}
备注:另外还有一种实现方式后续说明。
1.3 SpringApplication初始化
1.3.1 SpringBoot启动入口
想要启动一个SpringBoot应用很简单,只需要在包的根目录下创建一个类,并且在类上添加注解@SpringBootApplication标注其是一个SpringBoot应用即可:
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class,args);
}
}
通过执行该启动类的Main方法即可启动一个SpringBoot应用,接下来整个SpringBoot的启动过程就是通过SpringApplication的run方法来进行。
1.3.2 实例化SpringApplication
SpringApplication类可用于从main方法引导和启动Spring应用程序,默认情况下该类将执行以下步骤来引导程序的启动:
- 创建一个ApplicationContext上下文实例
- 注册CommandLinePropertySource以将命令行参数公开为Spring属性
- 刷新应用程序上下文并加载所有单例Bean
该类的初始化由该类调用自身的run方法开始,再调用自身重载的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);
}
上面的new SpringApplication(...)就是开始初始化该类的实例,点击构造方法进入得到以下初始化源码:
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
this.webApplicationType = WebApplicationType.deduceFromClasspath();
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}
核心的初始化分为以下三个步骤。
初始化WebApplicationType
应用类型的初始化通过WebApplicationType.deduceFromClasspath()来进行,点击进入其中查看对应源码:
public enum WebApplicationType {
NONE,
SERVLET,
REACTIVE;
private static final String[] SERVLET_INDICATOR_CLASSES = { "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";
static WebApplicationType deduceFromClasspath() {
if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null) && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)
&& !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {
return WebApplicationType.REACTIVE;
}
for (String className : SERVLET_INDICATOR_CLASSES) {
if (!ClassUtils.isPresent(className, null)) {
return WebApplicationType.NONE;
}
}
return WebApplicationType.SERVLET;
}
}
可以看出,通过反射判断环境是否存在这个类来判断获取初始化的web应用类型。
初始化Initializers
用于读取所有META-INF/spring.factories文件中配置了ApplicationContextInitializer的初始化器:
public void setInitializers(Collection<? extends ApplicationContextInitializer<?>> initializers) {
this.initializers = new ArrayList<>(initializers);
}
可以看出它将从spring.factories文件中获取的配置进行实例化后,封装成一个集合对SpringApplication中的initializers集合属性进行初始化。
初始化Listeners
跟初始化Initializers类似也是通过读取所有META-INF/spring.factories文件中配置的ApplicationListener类型的监听器,最终配置被实例化之后封装成一个集合对SpringApplication中的listeners集合属性进行初始化:
public void setListeners(Collection<? extends ApplicationListener<?>> listeners) {
this.listeners = new ArrayList<>(listeners);
}
值得注意的是,不管是初始化Initializers或者初始化Listeners,上面都省略了一个步骤,即读取配置和实例化的步骤,是因为它是一个通用读取的过程,以下详细讲解。
要读取配置中的组件信息,需要调用通用方式getSpringFactoriesInstances并传入对应的参数类型,例如:
# 读取ApplicationContextInitializer类型的配置信息
getSpringFactoriesInstances(ApplicationContextInitializer.class)
# 读取ApplicationListener类型的配置信息
getSpringFactoriesInstances(ApplicationListener.class)
这里列举了ApplicationContextInitializer类型和ApplicationListener类型在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.rsocket.context.RSocketPortInfoApplicationContextInitializer,\
org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializer
# Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.boot.ClearCachesApplicationListener,\
org.springframework.boot.builder.ParentContextCloserApplicationListener,\
org.springframework.boot.cloud.CloudFoundryVcapEnvironmentPostProcessor,\
org.springframework.boot.context.FileEncodingApplicationListener,\
org.springframework.boot.context.config.AnsiOutputApplicationListener,\
org.springframework.boot.context.config.ConfigFileApplicationListener,\
org.springframework.boot.context.config.DelegatingApplicationListener,\
org.springframework.boot.context.logging.ClasspathLoggingApplicationListener,\
org.springframework.boot.context.logging.LoggingApplicationListener,\
org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener
点击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) {
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;
}
可以看出最终它是由loadFactoryNames方法解析出配置并存放到Set集合中,最终将该集合作为参数传入createSpringFactoriesInstances方法,通过Set参数集合实例化出一个个实例。
而这里的Set集合就是一个个的ApplicationContextInitializer或ApplicationListener所对应的组件信息,点击loadFactoryNames方法进入,需要注意的是参数type为要读取的配置类型:
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
String factoryTypeName = factoryType.getName();
return (List)loadSpringFactories(classLoader).getOrDefault(factoryTypeName, 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 {
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();
String factoryTypeName = ((String)entry.getKey()).trim();
String[] var9 = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());
int var10 = var9.length;
for(int var11 = 0; var11 < var10; ++var11) {
String factoryImplementationName = var9[var11];
result.add(factoryTypeName, factoryImplementationName.trim());
}
}
}
cache.put(classLoader, result);
return result;
} catch (IOException var13) {
throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var13);
}
}
}
通过以上的loadSpringFactories方法,它遍历了每个jar包中的META-INF/spring.factories文件,并把spring.factories文件中的每个配置全部读取出来放到一个map中,每个map的key就是spring.factories文件中对应的一个属性配置key,value则是这个key所对应的一些需要初始化的组件,如下图展示其中一个spring.factories文件内容,以及读取出来的组件信息,以ApplicationContextInitializer类型为例:
# 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.rsocket.context.RSocketPortInfoApplicationContextInitializer,\
org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializer
该配置对应读取出来的map信息为:
最后在loadFactoryNames方法中通过factoryTypeName即ApplicationContextInitializer这个类型来筛选出其中的实现类,得到了以下结果:
这就是ApplicationContextInitializer类型的Set
private <T> List<T> createSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes,
ClassLoader classLoader, Object[] args, Set<String> names) {
List<T> instances = new ArrayList<>(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;
}
这段代码的意思就是将把spring.factories文件中的每个配置全部读取出来放到一个map中后,遍历该map的key,通过反射的方式实例化出来放到放instances集合中。
至此,整个SpringApplication实例初始化完成,而核心的属性Initializers和Listeners会在后续启动做作为重要参数来初始化。
1.4 Order注解实现
在前面的不管是Initializers或Listeners中通过添加@Order注解并指定优先级数值可以决定它们的执行顺序。上面的createSpringFactoriesInstances方法中返回了读取的例如Listeners实现,后续会将这些实现进行排序:
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
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;
}
AnnotationAwareOrderComparator
AnnotationAwareOrderComparator拓展了OrderComparator接口,它不仅支持Ordered接口,还支持@Order注解以方便排序。AnnotationAwareOrderComparator类图如下:
AnnotationAwareOrderComparator相较于父接口OrderComparator提供了通过读取注解元数据来进行排序的方法。
排序源码分析(以排序Initializers初始化器为例)
从上方可以知道实际排序的方法就是:
AnnotationAwareOrderComparator.sort(instances);
点击sort方法进入:
public class AnnotationAwareOrderComparator extends OrderComparator {
public static final AnnotationAwareOrderComparator INSTANCE = new AnnotationAwareOrderComparator();
public static void sort(List<?> list) {
if (list.size() > 1) {
list.sort(INSTANCE);
}
}
}
可以看出调用了ArrayList的sort方法并传入了AnnotationAwareOrderComparator,目的在于后续排序的时候调用了AnnotationAwareOrderComparator的父类OrderComparator方法doCompare执行排序。省略ArrayList的sort方法直接进入OrderComparator方法doCompare源码:
public class OrderComparator implements Comparator<Object> {
private int doCompare(@Nullable Object o1, @Nullable Object o2, @NullableOrderSourceProvider sourceProvider) {
boolean p1 = (o1 instanceof PriorityOrdered);
boolean p2 = (o2 instanceof PriorityOrdered);
if (p1 && !p2) {
return -1;
} else if (p2 && !p1) {
return 1;
}
int i1 = getOrder(o1, sourceProvider);
int i2 = getOrder(o2, sourceProvider);
return Integer.compare(i1, i2);
}
}
传递进来的参数Object o1和Object o2就是初始化器中的其中两个,开始对比这两者。点击getorder方法进入:
public class OrderComparator implements Comparator<Object> {
private int getOrder(@Nullable Object obj, @Nullable OrderSourceProvider sourceProvider) {
Integer order = null;
if ((obj != null) && (sourceProvider != null)) {
Object orderSource = sourceProvider.getOrderSource(obj);
if (orderSource != null) {
if (orderSource.getClass().isArray()) {
Object[] sources = ObjectUtils.toObjectArray(orderSource);
for (Object source : sources) {
order = findOrder(source);
if (order != null) {
break;
}
}
} else {
order = findOrder(orderSource);
}
}
}
return ((order != null) ? order : getOrder(obj)); // 由于sourceProvider为空所以直接走这里的方法
}
}
点击重载的getOrder方法:
public class OrderComparator implements Comparator<Object> {
protected int getOrder(@Nullable
Object obj) {
if (obj != null) { // 由于obj就是实际的初始化器所以这里不为空
Integer order = findOrder(obj);
if (order != null) {
return order;
}
}
return Ordered.LOWEST_PRECEDENCE;
}
}
跟踪findOrder方法进入:
public class AnnotationAwareOrderComparator extends OrderComparator {
@Override
@Nullable
protected Integer findOrder(Object obj) {
Integer order = super.findOrder(obj);
if (order != null) {
return order;
}
return findOrderFromAnnotation(obj);
}
@Override
@Nullable
protected Integer findOrder(Object obj) {
Integer order = super.findOrder(obj);
if (order != null) {
return order;
}
return findOrderFromAnnotation(obj);
}
@Nullable
private Integer findOrderFromAnnotation(Object obj) {
AnnotatedElement element = ((obj instanceof AnnotatedElement)
? (AnnotatedElement) obj : obj.getClass());
MergedAnnotations annotations = MergedAnnotations.from(element,
SearchStrategy.TYPE_HIERARCHY);
Integer order = OrderUtils.getOrderFromAnnotations(element, annotations);
if ((order == null) && obj instanceof DecoratingProxy) {
return findOrderFromAnnotation(((DecoratingProxy) obj).getDecoratedClass());
}
return order;
}
}
这里首先调用父类OrderComparator的findOrder方法,通过getOrder()方法获取初始化器的order属性值,若不存在该属性值,则findOrderFromAnnotation方法从注解元数据中获取,若获取结果仍然为空则返回默认的order值Ordered.LOWEST_PRECEDENCE。