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集合,拿到该集合后需要将集合中的ApplicationContextInitializer类型的实现进行一个个实例化出来,所以调用createSpringFactoriesInstances方法并将上述解析出来的实现集合作为参数传入(另外还有一个重要的参数即SpringApplication,这个后续绑定监听器时有用):

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。

posted @ 2020-07-17 22:40  飘飘来来荡荡去去  阅读(708)  评论(0编辑  收藏  举报