SpringBoot的启动很简单,通用的代码如下:

  1. @SpringBootApplication
  2. public class SpringBootDemoApplication {
  3. public static void main(String[] args) {
  4. SpringApplication.run(SpringBootDemoApplication.class, args);
  5. }
  6. }

SpringApplication.run()方法实际执行的方法如下:

  1. public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
  2. return run(new Class<?>[] { primarySource }, args);
  3. }

实则是:

  1. public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
  2. return new SpringApplication(primarySources).run(args);
  3. }

初始化SpringApplication

SpringApplication的构造函数:

  1. public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
  2. this.resourceLoader = resourceLoader;
  3. Assert.notNull(primarySources, "PrimarySources must not be null");
  4. this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
  5. // 调用WebApplicationType的静态方法deduceFromClasspath来选择启动的web应用类型
  6. this.webApplicationType = WebApplicationType.deduceFromClasspath();
  7. setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
  8. setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
  9. this.mainApplicationClass = deduceMainApplicationClass();
  10. }

(1)使用WebApplicationType的静态方法 deduceFromClasspath() 用来判断当前的应用是否是web应用,并设置到webApplicationType属性中去:

  1. static WebApplicationType deduceFromClasspath() {
  2. if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null) && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)
  3. && !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {
  4. return WebApplicationType.REACTIVE;
  5. }
  6. //非web应用情况
  7. for (String className : SERVLET_INDICATOR_CLASSES) {
  8. if (!ClassUtils.isPresent(className, null)) {
  9. return WebApplicationType.NONE;
  10. }
  11. }
  12. return WebApplicationType.SERVLET;
  13. }

SERVLET_INDICATOR_CLASSES数组里面的是什么类:

  1. private static final String[] SERVLET_INDICATOR_CLASSES = { "javax.servlet.Servlet",
  2. "org.springframework.web.context.ConfigurableWebApplicationContext" };

我们可以理解为: 如果获取不到这两个类:javax.servlet.Servlet”,”org.springframework.web.context.ConfigurableWebApplicationContext”, 则说明不是web应用。

(2)调用getSpringFactoriesInstances从spring.factories文件中找出key为ApplicationContextInitializer的类并实例化,然后调用setInitializers方法设置到SpringApplicationinitializers属性中。这个过程就是找出所有的应用程序初始化器。详情见获取初始化器。

  1. # Application Context Initializers
  2. org.springframework.context.ApplicationContextInitializer=\
  3. org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\
  4. org.springframework.boot.context.ContextIdApplicationContextInitializer,\
  5. org.springframework.boot.context.config.DelegatingApplicationContextInitializer,\
  6. org.springframework.boot.rsocket.context.RSocketPortInfoApplicationContextInitializer,\
  7. org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializer

(3)调用getSpringFactoriesInstances从spring.factories文件中找出key为ApplicationListener的类并实例化,然后调用setListeners方法设置到SpringApplicationlisteners属性中。这个过程就是找出所有的应用程序事件监听器。

获取初始化器

初始化器的获取由SpringApplication.getSpringFactoriesInstances方法完成:

  1. private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
  2. ClassLoader classLoader = getClassLoader();
  3. // Use names and ensure unique to protect against duplicates
  4. // 读取ApplicationContextInitializer的实现类
  5. Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
  6. // 实例化ApplicationContextInitializer的实现类
  7. List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
  8. AnnotationAwareOrderComparator.sort(instances);
  9. return instances;
  10. }

SpringFactoriesLoader.loadFactoryNames方法获取ApplicationContextInitializer接口实现的类:

  1. public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
  2. // 获取接口类的名称
  3. String factoryTypeName = factoryType.getName();
  4. return loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
  5. }
  1. private static Map<String, List> loadSpringFactories(@Nullable ClassLoader classLoader) {
  2. MultiValueMap<String, String> result = cache.get(classLoader);
  3. if (result != null) {
  4. return result;
  5. }
  6. try {
  7. // 获取FACTORIES_RESOURCE_LOCATION(META-INF/spring.factories)的多个位置
  8. Enumeration<URL> urls = (classLoader != null ?
  9. classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
  10. ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
  11. result = new LinkedMultiValueMap<>();
  12. while (urls.hasMoreElements()) {
  13. URL url = urls.nextElement();
  14. UrlResource resource = new UrlResource(url);
  15. Properties properties = PropertiesLoaderUtils.loadProperties(resource);
  16. for (Map.Entry<?, ?> entry : properties.entrySet()) {
  17. String factoryTypeName = ((String) entry.getKey()).trim();
  18. for (String factoryImplementationName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
  19. result.add(factoryTypeName, factoryImplementationName.trim());
  20. }
  21. }
  22. }
  23. cache.put(classLoader, result);
  24. return result;
  25. }
  26. catch (IOException ex) {
  27. throw new IllegalArgumentException("Unable to load factories from location [" +
  28. FACTORIES_RESOURCE_LOCATION + "]", ex);
  29. }
  30. }