从Springboot源码分析启动过程
这篇博客主要是通过Springboot的源码,分析Springboot项目的启动过程,深入理解spring的工作原理。其次,我对部分源码加上了注解,新手可以稍微看一下,同时我也希望大佬们能指出我理解有误的地方。
一、springboot启动源码解析
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();//项目计时器开始计时
ConfigurableApplicationContext context = null;
Collection exceptionReporters = new ArrayList<>();//异常处理类集合
configureHeadlessProperty();//设置System全局参数
SpringApplicationRunListeners listeners = getRunListeners(args);//SpringApplicationRunListener.class创建监视器实例
listeners.starting();//发起starting事件(event)
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);//将启动参数转换成spring能解析的格式,例如:--foo=bar --foo="tom"
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
configureIgnoreBeanInfo(environment);
Banner printedBanner = printBanner(environment);
context = createApplicationContext();//根据webApplicationType的类型创建Context对象实例
exceptionReporters = getSpringFactoriesInstances(
SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
prepareContext(context, environment, listeners, applicationArguments,
printedBanner);//准备项目运行的环境,加载xml文件中配置的bean
refreshContext(context);//更新Context 执行用户定义的postProcessBeanFactory操作,注册listener相关的bean,初始化所以剩下的单例类
afterRefresh(context, applicationArguments);//用户自定义的操作
stopWatch.stop();//项目计时器结束计时
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass)
.logStarted(getApplicationLog(), stopWatch);//打印日志信息
}
listeners.started(context);//发起ApplicationStartedEvent事件
callRunners(context, applicationArguments);//启动SpringApplication
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}
try {
listeners.running(context);//发起ApplicationReadyEvent事件
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
return context;
}
二、SpringApplication 类部分源码解析
/**
* 准备项目运行时的环境变量
* @param listeners 各种监听器
* @param applicationArguments 参数对象
* @return
*/
private ConfigurableEnvironment prepareEnvironment(
SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments) {
// Create and configure the environment
ConfigurableEnvironment environment = getOrCreateEnvironment();//初始化environment的Properties和configuration
configureEnvironment(environment, applicationArguments.getSourceArgs());//添加或替换commandLineArgs在environment中的属性值 确保profile被正确配置
listeners.environmentPrepared(environment);//发起ApplicationEnvironmentPreparedEvent事件
bindToSpringApplication(environment);
if (!this.isCustomEnvironment) {
environment = new EnvironmentConverter(getClassLoader())
.convertEnvironmentIfNecessary(environment, deduceEnvironmentClass());
}
ConfigurationPropertySources.attach(environment);
return environment;
}
/**
* 根据项目类型选择具体的环境参数类
* @return
*/
private Class extends StandardEnvironment> deduceEnvironmentClass() {
switch (this.webApplicationType) {
case SERVLET:
return StandardServletEnvironment.class;
case REACTIVE:
return StandardReactiveWebEnvironment.class;
default:
return StandardEnvironment.class;
}
}
/**
* 初始化项目上下文环境,具体的初始化内容看参数命名就清楚了
* @param context
* @param environment
* @param listeners
* @param applicationArguments
* @param printedBanner
*/
private void prepareContext(ConfigurableApplicationContext context,
ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments, Banner printedBanner) {
context.setEnvironment(environment);
postProcessApplicationContext(context);
applyInitializers(context);
listeners.contextPrepared(context);
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}
// Add boot specific singleton beans
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
if (printedBanner != null) {
beanFactory.registerSingleton("springBootBanner", printedBanner);
}
if (beanFactory instanceof DefaultListableBeanFactory) {
((DefaultListableBeanFactory) beanFactory)
.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
// Load the sources
Set
以后我会根据启动过程和你们一起慢慢的解析spring的各种相关的源码,有机会的话实现一个@EnableXXXX注解,已经实现但是有bug。