Spring Boot 2.x 启动全过程源码分析
SpringApplication 实例 run 方法运行过程
/**
* Run the Spring application, creating and refreshing a new 运行Spring应用程序,创建并刷新新的
* {@link ApplicationContext}. 应用上下文
* @param args the application arguments 应用程序参数(usually passed from a Java main method通常从java主方法传递)
* @return a running {@link ApplicationContext} 返回一个正在运行的应用上下文
*/
public ConfigurableApplicationContext run(String... args) {
//1.创建并启动计时监控类
StopWatch stopWatch = new StopWatch();
stopWatch.start();
// 2、初始化应用上下文
ConfigurableApplicationContext context = null;
//3.启动故障分析器
FailureAnalyzers analyzers = null;
//4.设置系统属性【java.awt.headless】,为true则启用headless模式支持
configureHeadlessProperty();
//5.通过*SpringFactoriesLoader*检索*META-INF/spring.factories*,
//找到声明的所有SpringApplicationRunListener的实现类并将其实例化,
//之后逐个调用其started()方法,广播SpringBoot要开始执行了。
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
try {
//6.初始化默认应用参数
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
//7.创建并配置当前SpringBoot应用将要使用的Environment(包括配置要使用的PropertySource以及Profile),
//并遍历调用所有的SpringApplicationRunListener的environmentPrepared()方法,广播Environment准备完毕。
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
//8.创建 Banner 打印类
Banner printedBanner = printBanner(environment);
//9.根据webEnvironment的值来决定创建何种类型的ApplicationContext对象
//如果是web环境,则创建org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext
//否则创建org.springframework.context.annotation.AnnotationConfigApplicationContext
context = createApplicationContext();
//10.注册启动故障分析器
analyzers = new FailureAnalyzers(context);
//11.为ApplicationContext加载environment,之后逐个执行ApplicationContextInitializer的initialize()方法
//来进一步封装ApplicationContext,
//并调用所有的SpringApplicationRunListener的contextPrepared()方法,
//EventPublishingRunListener只提供了一个空的contextPrepared()方 法,之后初始化IoC容器,
//并调用SpringApplicationRunListener的contextLoaded()方法,广播ApplicationContext的IoC加载完成,
//12.这里就包括通过**@EnableAutoConfiguration**导入的各种自动配置类。
//将listeners、environment、applicationArguments、banner等重要组件与上下文对象关联
prepareContext(context, environment, listeners, applicationArguments,
printedBanner);
//13.初始化所有自动配置类,调用ApplicationContext的refresh()方法
refreshContext(context);
//14.遍历所有注册的ApplicationRunner和CommandLineRunner,并执行其run()方法。
//该过程可以理解为是SpringBoot完成ApplicationContext初始化前的最后一步工作,
//我们可以实现自己的ApplicationRunner或者CommandLineRunner,来对SpringBoot的启动过程进行扩展。
afterRefresh(context, applicationArguments);
//15.调用所有的SpringApplicationRunListener的finished()方法,广播SpringBoot已经完成了ApplicationContext初始化的全部过程。
listeners.finished(context, null);
//16.关闭任务执行时间监听器
stopWatch.stop();
//17.如果开启日志,则打印执行是时间
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass)
.logStarted(getApplicationLog(), stopWatch);
}
return context;
}
catch (Throwable ex) {
//调用异常分析器打印报告,调用所有的SpringApplicationRunListener的finished()方法将异常信息发布出去
handleRunFailure(context, listeners, analyzers, ex);
throw new IllegalStateException(ex);
}
}
- 创建并启动计时监控类
/**
* 构造一个新的stopwatch 不能启动任何任务
*/
public StopWatch() {
this("");
}
/**
* 启动未命名的任务
*在不调用此方法的情况下(调用top方法) 调用计时方法,则结果是不确定的
*/
public void start() throws IllegalStateException {
start("");
}
public void start(String taskName) throws IllegalStateException {
if (this.running) {
throw new IllegalStateException("Can't start StopWatch: it's already running");
}
//是否正在运行
this.running = true;
//当前任务的名称
this.currentTaskName = taskName;
//开始时间
this.startTimeMillis = System.currentTimeMillis();
}
- 设置系统属性 java.awt.headless 的值
//设置jdk系统属性java.awt.headless,默认情况为true即开启;
private void configureHeadlessProperty() {
System.setProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS, System.getProperty(
SYSTEM_PROPERTY_JAVA_AWT_HEADLESS, Boolean.toString(this.headless)));
}
- 创建所有 Spring 运行监听器并发布应用启动事件
//根据args获取所有SpringApplicationRunListeners监听器
SpringApplicationRunListeners listeners = getRunListeners(args);
// 触发启动事件,启动监听器会被调用,一共5个监听器被调用
listeners.starting();
创建 Spring 运行监听器相关的源码:
private SpringApplicationRunListeners getRunListeners(String[] args) {
Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(
SpringApplicationRunListener.class, types, this, args));
}
//通过Class<?>[] types = new Class<?>[]{SpringApplication.class, String[].class};
//类型加载对应的监听器,并创建 SpringApplicationRunListener实例,
//看下’SpringApplicationRunListener’的构造方法
// 接受一个Log和Collection对象并赋给类成员变量
private final Log log;
private final List<SpringApplicationRunListener> listeners;
SpringApplicationRunListeners(Log log,
Collection<? extends SpringApplicationRunListener> listeners) {
this.log = log;
this.listeners = new ArrayList<SpringApplicationRunListener>(listeners);
}
我们重点看getSpringFactoriesInstances:
private <T> Collection<? extends T> getSpringFactoriesInstances(Class<T> type,
Class<?>[] parameterTypes, Object... args) {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
// Use names and ensure unique to protect against duplicates
Set<String> names = new LinkedHashSet<String>(
//这里用set来防止类被重复加载 loadFactoryNames(type, classLoader)来获取类的全限定名称,为后续进行实例化。
//这里获取的就是之前读 取spring.factories文件放到的cache中去拿,
//因为在spring.factories中根据类型SpringApplicationRunListener读取到的工厂类
//是EventPublishingRunListener(这是springboot统一处理事件的类)
SpringFactoriesLoader.loadFactoryNames(type, classLoader));
//这里创建事件处理的工厂实例
List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
classLoader, args, names);
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {
String factoryClassName = factoryClass.getName();
try {
// 通过类加载器获取resources; "META-INF/spring.factories"; 代码会去扫描项目工程中/META-INF下的spring.factories文件,获取 org.springframework.boot.SpringApplicationRunListener对应数据
Enumeration<URL> urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
List<String> result = new ArrayList<String>();
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url));
String propertyValue = properties.getProperty(factoryClassName);
for (String factoryName : StringUtils.commaDelimitedListToStringArray(propertyValue)) {
result.add(factoryName.trim());
}
}
return result;
}
catch (IOException ex) {
throw new IllegalArgumentException("Unable to load factories from location [" +
FACTORIES_RESOURCE_LOCATION + "]", ex);
}
}
public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
# Run Listeners
org.springframework.boot.SpringApplicationRunListener=\
org.springframework.boot.context.event.EventPublishingRunListener
由此可知this.getRunListeners(args) 最终拿到的是EventPublishingRunListener
- 初始化默认应用参数类
// 参数封装,也就是在命令行下启动应用带的参数,如--server.port=8081
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
5.根据运行监听器和应用参数来准备 Spring 环境
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
private ConfigurableEnvironment prepareEnvironment(
SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments) {
//Create and configure the environment 创建和配置环境
//获取或创建环境
ConfigurableEnvironment environment = getOrCreateEnvironment();
// 配置环境:配置PropertySources和activeProfiles
configureEnvironment(environment, applicationArguments.getSourceArgs());
//listeners环境准备(就是广播ApplicationEnvironmentPreparedEvent事件
listeners.environmentPrepared(environment);
//如果是非web环境,将环境转换成StandardEnvironment
if (!this.webEnvironment) {
environment = new EnvironmentConverter(getClassLoader())
.convertToStandardEnvironmentIfNecessary(environment);
}
return environment;
}
我们继续看下getOrCreateEnvironment:
// 获取或创建Environment,很显然我们这里是创建StandardServletEnvironment
private ConfigurableEnvironment getOrCreateEnvironment() {
// 存在则直接返回
if (this.environment != null) {
return this.environment;
}
// 根据webApplicationType创建对应的Environment
// webApplicationType的值还记得在哪获取到的吗?不知道的请去看我的springboot源码一
if (this.webApplicationType == WebApplicationType.SERVLET) {
// 标准的Servlet环境,也就是我们说的web环境
return new StandardServletEnvironment();
}
// 标准环境,非web环境
return new StandardEnvironment();
}
getOrCreateEnvironment方法创建并返回了一个环境:StandardServletEnvironment
我们继续往下看configureEnvironment:
protected void configureEnvironment(ConfigurableEnvironment environment,
String[] args) {
//配置PropertySource
configurePropertySources(environment, args);
//配置Profile
configureProfiles(environment, args);
}
我们来看 configurePropertySources的源码如下:
protected void configurePropertySources(ConfigurableEnvironment environment,
String[] args) {
MutablePropertySources sources = environment.getPropertySources();
//首先查看SpringApplication对象的成员变量defaultProperties,
//如果该变量非null且内容非空,则将其加入到Environment的PropertySource列表的最后
if (this.defaultProperties != null && !this.defaultProperties.isEmpty()) {
sources.addLast(
new MapPropertySource("defaultProperties", this.defaultProperties));
}
//然后查看SpringApplication对象的成员变量addCommandLineProperties和main函数的参数args,
//如果设置了addCommandLineProperties=true,且args个数大于0,
//那么就构造一个由main函数的参数组成的PropertySource放到Environment的PropertySource列表的最前面(这就能保证,
我们通过main函数的参数来做的配置是最优先的,可以覆盖其他配置)。
由于没有配置defaultProperties且main函数的参数args个数为0,所以这个函数什么也不做。
if (this.addCommandLineProperties && args.length > 0) {
String name = CommandLinePropertySource.COMMAND_LINE_PROPERTY_SOURCE_NAME;
if (sources.contains(name)) {
PropertySource<?> source = sources.get(name);
CompositePropertySource composite = new CompositePropertySource(name);
composite.addPropertySource(new SimpleCommandLinePropertySource(
name + "-" + args.hashCode(), args));
composite.addPropertySource(source);
sources.replace(name, composite);
}
else {
// 将其放到第一位置
sources.addFirst(new SimpleCommandLinePropertySource(args));
}
}
}
我们接下来看configureProfiles:
//首先会读取Properties中key为spring.profiles.active的配置项,配置到Environment,
//然后再将SpringApplication对象的成员变量additionalProfiles加入到Environment的active profiles配置中
protected void configureProfiles(ConfigurableEnvironment environment, String[] args) {
//保证environment的activeProfiles属性被初始化了。
environment.getActiveProfiles(); // ensure they are initialized
// 如果存在其他的Profiles,则将这些Profiles放到第一的位置。
// But these ones should go first (last wins in a property key clash)
Set<String> profiles = new LinkedHashSet<String>(this.additionalProfiles);
profiles.addAll(Arrays.asList(environment.getActiveProfiles()));
environment.setActiveProfiles(profiles.toArray(new String[profiles.size()]));
}
接着来看 listeners.environmentPrepared(environment):
listeners.environmentPrepared(environment);
//广播ApplicationEnvironmentPreparedEvent事件
public void environmentPrepared(ConfigurableEnvironment environment) {
for (SpringApplicationRunListener listener : this.listeners) {
listener.environmentPrepared(environment);
}
}
6.创建 Banner 打印类
Banner printedBanner = printBanner(environment);
private Banner printBanner(ConfigurableEnvironment environment) {
if (this.bannerMode == Banner.Mode.OFF) {
return null;
}
ResourceLoader resourceLoader = (this.resourceLoader != null)
? this.resourceLoader : new DefaultResourceLoader(getClassLoader());
SpringApplicationBannerPrinter bannerPrinter = new SpringApplicationBannerPrinter(
resourceLoader, this.banner);
if (this.bannerMode == Mode.LOG) {
return bannerPrinter.print(environment, this.mainApplicationClass, logger);
}
return bannerPrinter.print(environment, this.mainApplicationClass, System.out);
}
7.创建应用上下文
context = createApplicationContext();
// 根据SpringApplication的webEnvironment来实例化对应的上下文;如果webEnvironment的值是true,
//那么实例化AnnotationConfigEmbeddedWebApplicationContext,
//如果是false则实例化 AnnotationConfigApplicationContext
protected ConfigurableApplicationContext createApplicationContext() {
Class<?> contextClass = this.applicationContextClass;
if (contextClass == null) {
try {
contextClass = Class.forName(this.webEnvironment
? DEFAULT_WEB_CONTEXT_CLASS : DEFAULT_CONTEXT_CLASS);
}
catch (ClassNotFoundException ex) {
throw new IllegalStateException(
"Unable create a default ApplicationContext, "
+ "please specify an ApplicationContextClass",
ex);
}
}
//利用反射调用其中一个ApplicationContext的构造方法进行实例化
return (ConfigurableApplicationContext) BeanUtils.instantiate(contextClass);
}
8.初始化了FailureAnalyzers
analyzers = new FailureAnalyzers(context);
FailureAnalyzers(ConfigurableApplicationContext context, ClassLoader classLoader) {
Assert.notNull(context, "Context must not be null");
this.classLoader = (classLoader != null) ? classLoader : context.getClassLoader();
//初始化在spring.factory文件中的名称为:“org.springframework.boot.diagnostics.FailureAnalyzer”的对象
this.analyzers = loadFailureAnalyzers(this.classLoader);
//这个方法就是触发初始化的FailureAnalyzer对象,如果是BeanFactoryAware类型的,
//则调用其setBeanFactory方法,需要注意的是,此时的bean,还没有加载,
//bean的加载过程还在后面,所以此时获取的beanFactory是没有bean属性的
prepareFailureAnalyzers(this.analyzers, context);
}
9.准备应用上下文
/**
* 准备应用上下文
* @param context AnnotationConfigServletWebServerApplicationContext实例
* @param environment SpringApplication中的StandardServletEnvironment实例
* @param applicationArguments SpringApplication中的DefaultApplicationArguments实例
* @param printedBanner 默认使用SpringApplicationBanner实例
*/
private void prepareContext(ConfigurableApplicationContext context,
ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments, Banner printedBanner) {
//设置context(上下文)环境
//统一ApplicationContext和Application,使用Application的environment
context.setEnvironment(environment);
//ApplicationContext的后置处理
postProcessApplicationContext(context);
//执行Initializers
applyInitializers(context);
//发布contextPrepared事件
listeners.contextPrepared(context);
if (this.logStartupInfo) {
//配置了info日志
//打印启动和profile日志
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}
//获取到DefaultListableBeanFactory实例
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
//注册名为springApplicationArguments,值为applicationArguments的单例bean
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
//banner不为空,那么注册名为springBootBanner,值为printedBanner的单例bean
if (printedBanner != null) {
beanFactory.registerSingleton("springBootBanner", printedBanner);
}
if (beanFactory instanceof DefaultListableBeanFactory) {
//allowBeanDefinitionOverriding默认为false
((DefaultListableBeanFactory) beanFactory)
.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
// 获取sources列表,获取到我们的YanggxApplication.class
Set<Object> sources = getAllSources();
Assert.notEmpty(sources, "Sources must not be empty");
//初始化bean加载器,并加载bean到应用上下文
load(context, sources.toArray(new Object[0]));
//发布contextLoaded事件
listeners.contextLoaded(context);
}
}
10.刷新应用上下文
refreshContext(context);
private void refreshContext(ConfigurableApplicationContext context) {
//这里面最重要的就是这个refresh方法,我们继续跟进
refresh(context);
if (this.registerShutdownHook) {
try {
context.registerShutdownHook();
}
catch (AccessControlException ex) {
// Not allowed in some environments.
}
}
}
protected void refresh(ApplicationContext applicationContext) {
//继续进入refresh方法
Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);
((AbstractApplicationContext) applicationContext).refresh();
}
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 准备刷新
prepareRefresh();
// 通知子类刷新内部bean工厂
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 准备bean工厂以便在此上下文中使用
prepareBeanFactory(beanFactory);
try {
// 允许上下文子类中对bean工厂进行后处理
postProcessBeanFactory(beanFactory);
// 在bean创建之前调用BeanFactoryPostProcessors后置处理方法
invokeBeanFactoryPostProcessors(beanFactory);
// 注册BeanPostProcessor
registerBeanPostProcessors(beanFactory);
// 注册DelegatingMessageSource
initMessageSource();
// 注册multicaster
initApplicationEventMulticaster();
// 创建内置的Servlet容器
onRefresh();
// 注册Listener
registerListeners();
// 完成BeanFactory初始化,初始化剩余单例bean
finishBeanFactoryInitialization(beanFactory);
// 发布对应事件
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}
此方法由于内容比较多,下次重开一篇博客专门跟进!
11.应用上下文刷新后置处理
afterRefresh(context, applicationArguments);
//在刷新上下文后调用
protected void afterRefresh(ConfigurableApplicationContext context,
ApplicationArguments args) {
callRunners(context, args);
}
//如果实现了ApplicationRunner或CommandLineRunner就去调用实现的方法
private void callRunners(ApplicationContext context, ApplicationArguments args) {
List<Object> runners = new ArrayList<Object>();
runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
AnnotationAwareOrderComparator.sort(runners);
for (Object runner : new LinkedHashSet<Object>(runners)) {
if (runner instanceof ApplicationRunner) {
callRunner((ApplicationRunner) runner, args);
}
if (runner instanceof CommandLineRunner) {
callRunner((CommandLineRunner) runner, args);
}
}
}
12.调用所有的SpringApplicationRunListener的finished()方法,广播SpringBoot已经完成了ApplicationContext初始化的全部过程。
private void callFinishedListener(SpringApplicationRunListener listener,
ConfigurableApplicationContext context, Throwable exception) {
try {
listener.finished(context, exception);
}
catch (Throwable ex) {
if (exception == null) {
ReflectionUtils.rethrowRuntimeException(ex);
}
if (this.log.isDebugEnabled()) {
this.log.error("Error handling failed", ex);
}
else {
String message = ex.getMessage();
message = (message != null) ? message : "no error message";
this.log.warn("Error handling failed (" + message + ")");
}
}
}
@Override
public void finished(ConfigurableApplicationContext context, Throwable exception) {
SpringApplicationEvent event = getFinishedEvent(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);
}
}
if (event instanceof ApplicationFailedEvent) {
this.initialMulticaster.setErrorHandler(new LoggingErrorHandler());
}
this.initialMulticaster.multicastEvent(event);
}
}
13.停止计时监控类
stopWatch.stop();
public void stop() throws IllegalStateException {
//没有启动抛出异常
if (!this.running) {
throw new IllegalStateException("Can't stop StopWatch: it's not running");
}
//启动完成时间
long lastTime = System.currentTimeMillis() - this.startTimeMillis;
//启动总时间
this.totalTimeMillis += lastTime;
//内部类,用于保存有关在秒表中执行的一个任务的数据
this.lastTaskInfo = new TaskInfo(this.currentTaskName, lastTime);
if (this.keepTaskList) {
this.taskList.add(lastTaskInfo);
}
//返回定时任务的数量
++this.taskCount;
//启动标识设false
this.running = false;
//置空当前线程名称
this.currentTaskName = null;
}
计时监听器停止,并统计一些任务执行信息。
14.输出日志记录执行主类名、时间信息
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass)
.logStarted(getApplicationLog(), stopWatch);
}