[SpringBoot源码分析]SpringBoot是如何启动的

SpringBoot概念

  • SpringApplication提供了从main方法开始的启动spring应用程序的便捷方法。
  • Spring Boot 基于 spring4.0以后

特点

  • 快速开发和构建微服务系统
  • 内嵌容器,如 Tomcat、Undertow
  • 自动加载
  • 自动管理依赖

引言

  • 那么上述的springboot有这么多好处,那先研究下springboot是怎么启动,后续我们再分篇研究下自动加载

开始分析源码

@SpringBootApplication(scanBasePackages = {"com.github.demo"})
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}
// SpringApplication的run方法
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
   return run(new Class<?>[] { primarySource }, args);
}
// 最终调用的SpringApplication的run方法
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
   return new SpringApplication(primarySources).run(args);
}
复制代码

初始化SpringApplication

public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
   // 设置 resource
   this.resourceLoader = resourceLoader;
   Assert.notNull(primarySources, "PrimarySources must not be null");
   
   this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
   // 初始化类型 是 web 还是 reactor
   this.webApplicationType = WebApplicationType.deduceFromClasspath();
   
   // 从类路径下找到META‐INF/spring.factories文件中,加载ApplicationContextInitializer接口的实现类, 并设置
   setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
   
    // 从类路径下找到META‐INF/spring.factories文件中,ApplicationListener接口的实现类,并设置
   setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
   this.mainApplicationClass = deduceMainApplicationClass();
}
复制代码

ApplicationContextInitializer

定义

Spring容器刷新之前,初始化ConfigurableApplicationContext上下文的回调接口 ApplicationContextInitializer是Spring框架原有的产物

实现类

# 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
复制代码

ApplicationListener

定义

ApplicationListener:监听spring容器中发布的事件

实现类

# 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
复制代码

核心的运行方法

// 运行springboot应用, 创建并且刷新ApplicationContext.
public ConfigurableApplicationContext run(String... args) {
   // 1.计时器   非重点
   StopWatch stopWatch = new StopWatch();
   stopWatch.start();
   
   ConfigurableApplicationContext context = null;
   // 2.支持报告spring应用启动错误  非重点
   Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
   configureHeadlessProperty();
   
   // 3.获取listener   重点
   SpringApplicationRunListeners listeners = getRunListeners(args);
   // 3.1 调用启动中事件的方法 重点
   listeners.starting();
   
   try {
       // 4. ApplicationArguments  重点
      ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
      // 5. 预处理环境参数 重点
      ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
      configureIgnoreBeanInfo(environment);
      // 6. 打印Banner 非重点
      Banner printedBanner = printBanner(environment);
      
      // 7.创建ApplicationContext
      context = createApplicationContext();
      
      // 8.通过spi获取错误报告类 非重点
      exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
            new Class[] { ConfigurableApplicationContext.class }, context);
      // 9. 预处理上下文       重点
      prepareContext(context, environment, listeners, applicationArguments, printedBanner);
      // 10. 刷新上下文 重点
      refreshContext(context);
      // 11. 后置处理 重点
      afterRefresh(context, applicationArguments);
      // 12. 计时器处理 非重点
      stopWatch.stop();
      if (this.logStartupInfo) {
         new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
      }
      // 13. 调用启动事件的方法 重点
      listeners.started(context);
      // 14. 调用实现ApplicationRunner和CommandLineRunner的方法  重点
      callRunners(context, applicationArguments);
   }
   catch (Throwable ex) {
     // 15.异常处理 重点
      handleRunFailure(context, ex, exceptionReporters, listeners);
      throw new IllegalStateException(ex);
   }

   try {
      // 16. 调用运行中事件 重点
      listeners.running(context);
   }
   catch (Throwable ex) {
   	// 17 异常处理 重点
      handleRunFailure(context, ex, exceptionReporters, null);
      throw new IllegalStateException(ex);
   }
   return context;
}

复制代码

解释 3.获取事件监听

private SpringApplicationRunListeners getRunListeners(String[] args) {
   Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
   return new SpringApplicationRunListeners(logger,
         getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));
}
复制代码

注:通过SPI加载SpringApplicationRunListener接口的所有实现

SpringApplicationRunListener 生命周期

定义

spring应用运行方法的收听者

7个阶段

default void starting() {
}
default void environmentPrepared(ConfigurableEnvironment environment) {
}

default void contextPrepared(ConfigurableApplicationContext context) {
}

default void contextLoaded(ConfigurableApplicationContext context) {
}

default void started(ConfigurableApplicationContext context) {
}

default void running(ConfigurableApplicationContext context) {
}

default void failed(ConfigurableApplicationContext context, Throwable exception) {
}
复制代码

实现类

在spring.factories文件定义了SpringApplicationRunListener的实现类

# Run Listeners
org.springframework.boot.SpringApplicationRunListener=\
org.springframework.boot.context.event.EventPublishingRunListener
复制代码

EventPublishingRunListener类的实现接口的七个阶段

@Override
public void starting() {
// 广播开始的事件
   this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args));
}

@Override
public void environmentPrepared(ConfigurableEnvironment environment) {
   this.initialMulticaster
         .multicastEvent(new ApplicationEnvironmentPreparedEvent(this.application, this.args, environment));
}

@Override
public void contextPrepared(ConfigurableApplicationContext context) {
   this.initialMulticaster
         .multicastEvent(new ApplicationContextInitializedEvent(this.application, this.args, context));
}

@Override
public void contextLoaded(ConfigurableApplicationContext context) {
   for (ApplicationListener<?> listener : this.application.getListeners()) {
      if (listener instanceof ApplicationContextAware) {
         ((ApplicationContextAware) listener).setApplicationContext(context);
      }
      context.addApplicationListener(listener);
   }
   this.initialMulticaster.multicastEvent(new ApplicationPreparedEvent(this.application, this.args, context));
}

@Override
public void started(ConfigurableApplicationContext context) {
   context.publishEvent(new ApplicationStartedEvent(this.application, this.args, context));
}

@Override
public void running(ConfigurableApplicationContext context) {
   context.publishEvent(new ApplicationReadyEvent(this.application, this.args, context));
}

@Override
public void failed(ConfigurableApplicationContext context, Throwable exception) {
   ApplicationFailedEvent event = new ApplicationFailedEvent(this.application, this.args, context, exception);
   if (context != null && context.isActive()) {
      // Listeners have been registered to the application context so we should
      // use it at this point if we can
      context.publishEvent(event);
   }
   else {
      // An inactive context may not have a multicaster so we use our multicaster to
      // call all of the context's listeners instead
      if (context instanceof AbstractApplicationContext) {
         for (ApplicationListener<?> listener : ((AbstractApplicationContext) context)
               .getApplicationListeners()) {
            this.initialMulticaster.addApplicationListener(listener);
         }
      }
      this.initialMulticaster.setErrorHandler(new LoggingErrorHandler());
      this.initialMulticaster.multicastEvent(event);
   }
}
复制代码

注:EventPublishingRunListener类的实现其实就是在不同阶段广播不同的事件

CommandLineRunner

定义

属于springboot应用的扩展点,在springboot应用的applicationContext初始化后开始被执行的

@FunctionalInterface
public interface CommandLineRunner {

   /**
    * Callback used to run the bean.
    * @param args incoming main method arguments
    * @throws Exception on error
    */
   void run(String... args) throws Exception;

}
复制代码

ApplicationRunner

定义

@FunctionalInterface
public interface ApplicationRunner {

   /**
    * Callback used to run the bean.
    * @param args incoming application arguments
    * @throws Exception on error
    */
   void run(ApplicationArguments args) throws Exception;

}
复制代码

构建ApplicationArguments

public interface ApplicationArguments {
    String[] getSourceArgs();
    Set<String> getOptionNames();
    boolean containsOption(String name);
    List<String> getOptionValues(String name);
    List<String> getNonOptionArgs();
}
复制代码
public class DefaultApplicationArguments implements ApplicationArguments {

	private final Source source;

	private final String[] args;

	public DefaultApplicationArguments(String... args) {
		Assert.notNull(args, "Args must not be null");
		this.source = new Source(args);
		this.args = args;
	}
	......
	private static class Source extends SimpleCommandLinePropertySource {

		Source(String[] args) {
			super(args);
		}

	}

}
复制代码

创建ApplicationContext

public static final String DEFAULT_CONTEXT_CLASS = "org.springframework.context."
		+ "annotation.AnnotationConfigApplicationContext";

public static final String DEFAULT_SERVLET_WEB_CONTEXT_CLASS = "org.springframework.boot."
		+ "web.servlet.context.AnnotationConfigServletWebServerApplicationContext";

public static final String DEFAULT_REACTIVE_WEB_CONTEXT_CLASS = "org.springframework."
		+ "boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext";

protected ConfigurableApplicationContext createApplicationContext() {
	Class<?> contextClass = this.applicationContextClass;
	if (contextClass == null) {
		try {
			switch (this.webApplicationType) {
			case SERVLET:
				contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
				break;
			case REACTIVE:
				contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
				break;
			default:
				contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
			}
		}
		catch (ClassNotFoundException ex) {
			throw new IllegalStateException(
					"Unable create a default ApplicationContext, please specify an ApplicationContextClass", ex);
		}
	}
	return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
}
复制代码

注:

  • 这个比较简单,就是通过org.springframework.boot.WebApplicationType创建不同的ApplicationContext

预处理上下文(prepareContext方法)

private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
			SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
		// 设置容器的变量
		context.setEnvironment(environment);
		// 执行容器的后置处理
		postProcessApplicationContext(context);
		// 在上下文刷新之前,将ApplicationContextInitializer应用到上下文中。
		applyInitializers(context);
		// 广播上下文已经准备好的事件
		listeners.contextPrepared(context);
		
		if (this.logStartupInfo) {
			logStartupInfo(context.getParent() == null);
			logStartupProfileInfo(context);
		}
		// Add boot specific singleton beans
		// 在容器中注入applicationArguments 的bean
		ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
		beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
		if (printedBanner != null) {
			beanFactory.registerSingleton("springBootBanner", printedBanner);
		}
		if (beanFactory instanceof DefaultListableBeanFactory) {
			((DefaultListableBeanFactory) beanFactory)
					.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
		}
		if (this.lazyInitialization) {
			context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
		}
		// Load the sources
		Set<Object> sources = getAllSources();
		Assert.notEmpty(sources, "Sources must not be empty");
		
		// 加载我们的启动类,将启动类注入容器
		load(context, sources.toArray(new Object[0]));
		// 广播容器已加载的事件
		listeners.contextLoaded(context);
	}
复制代码

刷新上下文

private void refreshContext(ConfigurableApplicationContext context) {
		if (this.registerShutdownHook) {
			try {
				// 注册容器关闭之前做一些资源回收的操作
				context.registerShutdownHook();
			}
			catch (AccessControlException ex) {
				// Not allowed in some environments.
			}
		}
		refresh(context);
	}
复制代码

真正调用AbstractApplicationContext#refresh

protected void refresh(ApplicationContext applicationContext) {
		Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);
		((AbstractApplicationContext) applicationContext).refresh();
	}
复制代码

AbstractApplicationContext#refresh 这个方法主要是spring应用上下文生命周期的方法,这里只做简单的介绍,不往深处深究了

public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // 留给子类去实现创建BeanFactory. ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

		// 预处理BeanFactory对象
		prepareBeanFactory(beanFactory);

		try {
			// 允许子类中对BeanFactory进行后期处理.
			postProcessBeanFactory(beanFactory);

			// I调用注册为BeanFactory的工厂处理器
			invokeBeanFactoryPostProcessors(beanFactory);

			// 注册实现BeanPostProcessor接口的bean后置处理类
			registerBeanPostProcessors(beanFactory);

			// 初始化application实现广播器
			initApplicationEventMulticaster();

			// 又是留给子类实现刷新操作额
			onRefresh();

			// 检查bean的***并注册它们。.
			registerListeners();

			//完成Bean的初始化
			finishBeanFactoryInitialization(beanFactory);

			// 发布上下文刷新完成的时间
			finishRefresh();
		}catch (BeansException ex) {
			// Propagate exception to caller.
			throw ex;
		}finally {
			resetCommonCaches();
		}
	}
}
复制代码

后置处理

protected void afterRefresh(ConfigurableApplicationContext context, ApplicationArguments args) {
	}
复制代码

这里是空方法,需要子类自己实现

调用启动事件的方法

void started(ConfigurableApplicationContext context) {
		for (SpringApplicationRunListener listener : this.listeners) {
			listener.started(context);
		}
	}
复制代码

调用实现ApplicationRunner和CommandLineRunner的方法

private void callRunners(ApplicationContext context, ApplicationArguments args) {
		List<Object> runners = new ArrayList<>();
		runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
		runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
		//排序
		AnnotationAwareOrderComparator.sort(runners);
		for (Object runner : new LinkedHashSet<>(runners)) {
			if (runner instanceof ApplicationRunner) {
				callRunner((ApplicationRunner) runner, args);
			}
			if (runner instanceof CommandLineRunner) {
				callRunner((CommandLineRunner) runner, args);
			}
		}
	}
复制代码

总结

  • 运用了观察者模式
  • 运用SPI技术来动态加载具体的实现类,dubbo也是这样实现的,想了解dubbo的spi可以查看下面文章:juejin.cn/post/697392…
  • SpringBoot启动加载器有两种方式:CommandLineRunner和ApplicationRunner,并且是在应用程序启动完成后
  • CommandLineRunner和ApplicationRunner的执行顺序,是将他们都统一添加到同一个list 然后根据@Order注解派去