版本:2.1.1.RELEASE
使用main方法启动Spring Boot应用:
public static void main(String[] args) {
SpringApplication.run(DingtalkApplication.class, args);
}
进入SpringApplication类的run方法最终实现位置:
public ConfigurableApplicationContext run(String... args) {
// 1. 启动计时
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
// 2. 回调接口SpringBootExceptionReporter用于支持自定义spring应用程序启动错误的报告
Collection exceptionReporters = new ArrayList<>();
// 3. 配置启用Java headless模式
configureHeadlessProperty();
// 4. 获取Spring应用run方法的监听器集合并启动所有的监听器
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
try {
// 5. 提供对用于运行SpringApplication的参数的访问
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
// 6. 创建和配置环境
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
// 7. 配置忽略BeanInfo类的加载
configureIgnoreBeanInfo(environment);
// 8. 打印Banner
Banner printedBanner = printBanner(environment);
// 9. 创建ApplicationContext
context = createApplicationContext();
// 10. 获取异常报告实例列表
exceptionReporters = getSpringFactoriesInstances(
SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
// 11. 准备应用上下文
prepareContext(context, environment, listeners, applicationArguments,
printedBanner);
// 12. 刷新底层的ApplicationContext
refreshContext(context);
// 13. protected方法,应用上下文刷新后,子类可实现此方法用于后续的操作
afterRefresh(context, applicationArguments);
// 14. 打印应用启动信息
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass)
.logStarted(getApplicationLog(), stopWatch);
}
// 15. 启动实现了CommandLineRunner 和 ApplicationRunner 接口的类的run方法
listeners.started(context);
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}
try {
// 16. 在run 方法结束之前立即调用,发布事件,应用程序已准备好接受服务请求
listeners.running(context);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
return context;
}
run方法源码上注释了大概流程,接下来继续深入重点流程的源码。
流程4,获取Spring应用run方法的监听器集合并启动所有的监听器:
getRunListeners(String[] args) 方法源码:
private SpringApplicationRunListeners getRunListeners(String[] args) {
Class>[] types = new Class>[] { SpringApplication.class, String[].class };
return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(
SpringApplicationRunListener.class, types, this, args));
}
返回SpringApplicationRunListeners 实例,直接看构造方法的第二个参数的getSpringFactoriesInstances方法实现:
private Collection getSpringFactoriesInstances(Class type,
Class>[] parameterTypes, Object... args) {
// 1. 获取类加载器
ClassLoader classLoader = getClassLoader();
// 2. 获取指定类型的工厂实现类的完全限定类名集合
Set names = new LinkedHashSet<>(
SpringFactoriesLoader.loadFactoryNames(type, classLoader));
// 3. 根据传入的完全限定类名集合创建对应工厂实例
List instances = createSpringFactoriesInstances(type, parameterTypes,
classLoader, args, names);
// 4. 根据工厂实例上的@Order注解指定的顺序排序
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
该方法第一个参数这里传入的是SpringApplicationRunListener 接口,会获取该接口所在类加载器下的“META-INF/spring.factories”属性文件
设置的接口实现org.springframework.boot.context.event.EventPublishingRunListener,然后调用该类的构造方法实例化:
public EventPublishingRunListener(SpringApplication application, String[] args) {
this.application = application;
this.args = args;
this.initialMulticaster = new SimpleApplicationEventMulticaster();
for (ApplicationListener> listener : application.getListeners()) {
this.initialMulticaster.addApplicationListener(listener);
}
}
该类的主要作用是作为应用启动过程的事件发布监听器,可以看到构造方法中实例化了一个简单的应用事件多播器SimpleApplicationEventMulticaster 并遍历添加应用启动事件监听器。
流程4最后调用listeners.starting() 启动监听器,实现源码:
@Override
public void starting() {
this.initialMulticaster.multicastEvent(
new ApplicationStartingEvent(this.application, this.args));
}
该方法多播一个ApplicationStartingEvent实例(应用启动事件),事件源是SpringApplication本身。
接下来就是解析事件类型并调用对应的事件监听器了,感兴趣的可以自己深入。深入之前需要对Spring事件机制有所了解,
推荐此文Spring事件机制。
流程6. 创建和配置环境:
prepareEnvironment(listeners, applicationArguments)方法实现:
private ConfigurableEnvironment prepareEnvironment(
SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments) {
// 创建环境
ConfigurableEnvironment environment = getOrCreateEnvironment();
// 配置环境
configureEnvironment(environment, applicationArguments.getSourceArgs());
// 发布环境准备事件
listeners.environmentPrepared(environment);
// 绑定环境到此应用
bindToSpringApplication(environment);
// 判断是否需要转换环境
if (!this.isCustomEnvironment) {
environment = new EnvironmentConverter(getClassLoader())
.convertEnvironmentIfNecessary(environment, deduceEnvironmentClass());
}
// 附加ConfigurationPropertySource支持到指定环境
ConfigurationPropertySources.attach(environment);
return environment;
}
其中,getOrCreateEnvironment() 方法实现:
private ConfigurableEnvironment getOrCreateEnvironment() {
if (this.environment != null) {
return this.environment;
}
// 根据ClassPath存在的类推断应用运行环境,以下都是web环境
switch (this.webApplicationType) {
case SERVLET:
return new StandardServletEnvironment();
case REACTIVE:
return new StandardReactiveWebEnvironment();
default:
return new StandardEnvironment();
}
}
流程9. 创建ApplicationContext:
createApplicationContext方法实现:
protected ConfigurableApplicationContext createApplicationContext() {
Class> contextClass = this.applicationContextClass;
if (contextClass == null) {
try {
switch (this.webApplicationType) {
case SERVLET:
// 1. 初始化并返回org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext Class对象
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);
}
}
// 忽略异常捕获代码
}
// 2. 调用AnnotationConfigServletWebServerApplicationContext对象的默认构造方法实例化
return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
}
流程11. 准备应用上下文:
prepareContext方法实现:
private void prepareContext(ConfigurableApplicationContext context,
ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments, Banner printedBanner) {
// 1. 设置环境
context.setEnvironment(environment);
// 2. 在ApplicationContext中应用任何相关的后置处理,这里为context对象的BeanFactory实例DefaultListableBeanFactory添加转换服务
postProcessApplicationContext(context);
// 3. 在context刷新之前应用实现了ApplicationContextInitializer回调接口的实例进行context上下文对象的初始化
applyInitializers(context);
// 4. 发布context初始化事件
listeners.contextPrepared(context);
// 5. 打印应用版本信息和激活的配置文件信息active profile
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}
// 6. 添加名称为springApplicationArguments,springBootBanner的单例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);
}
// 7. 加载源(即main方法所在的类对象)不可变的集合对象并注册其bean到应用上下文
Set
应用上下文对象准备好了,接下来就进行刷新上下文操作。
12. 刷新底层的ApplicationContext:
refreshContext方法实现:
private void refreshContext(ConfigurableApplicationContext context) {
refresh(context);
if (this.registerShutdownHook) {
try {
// 向JVM运行时注册一个关机钩子,在JVM关闭时同时关闭这个上下文。
context.registerShutdownHook();
}
......
}
}
进入到ServletWebServerApplicationContext类的refresh(context)方法实现:
@Override
public final void refresh() throws BeansException, IllegalStateException {
try {
super.refresh();
}
......
}
发现是直接调用的父类AbstractApplicationContext的refresh方法实现:
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 1. 准备好刷新上下文
prepareRefresh();
// 2. 告诉子类刷新内部bean工厂
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 3. 准备bean工厂以用于此上下文中
prepareBeanFactory(beanFactory);
try {
// 4. 允许在特定的ApplicationContext实现中注册特殊的bean后置处理器
postProcessBeanFactory(beanFactory);
// 5. 实例化并调用所有已注册的BeanFactoryPostProcessor bean
invokeBeanFactoryPostProcessors(beanFactory);
// 6. 实例化并调用所有已注册的BeanPostProcessor bean
registerBeanPostProcessors(beanFactory);
// 7. 初始化MessageSource用于当前上下文,提供参数化和i18n的支持
initMessageSource();
// 8. 初始化事件多路广播用于当前上下文,默认使用SimpleApplicationEventMulticaster单例bean
initApplicationEventMulticaster();
// 9. 在特定上下文子类中初始化其他特殊bean。
onRefresh();
// 10. 检查监听器bean并注册它们
registerListeners();
// 11. 实例化剩余所有非懒加载的单例bean
finishBeanFactoryInitialization(beanFactory);
// 12. 最后一步: 发布相应的事件
finishRefresh();
}
catch (BeansException ex) {
......
// 销毁所有创建的单例来避免悬空资源
destroyBeans();
// 重置 'active' 标识.
cancelRefresh(ex);
// 抛出异常给调用者
throw ex;
}
finally {
// 重置Spring的公共反射元数据缓存
resetCommonCaches();
}
}
}
第一点主要做了以下操作:
第二点主要做了以下操作:
第三点主要做了以下操作:
第四点主要做了以下操作:
第五点主要做了以下操作:
第六点主要做了以下操作:
第九点主要做了以下操作:
第十一点完成BeanFactory的初始化并实例化剩余的单例bean:
finishBeanFactoryInitialization方法实现:
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
// 初始化用于此上下文的转换服务
if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
beanFactory.setConversionService(
beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
}
// 如果没有内嵌value解析器Bean则注册一个(例如 PropertyPlaceholderConfigurer bean),主要用于解析${}占位符.
if (!beanFactory.hasEmbeddedValueResolver()) {
beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
}
// 尽早地初始化LoadTimeWeaverAware bean以允许尽早地注册其变换器
String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
for (String weaverAwareName : weaverAwareNames) {
getBean(weaverAwareName);
}
// 停止正用于类型匹配的临时类加载器
beanFactory.setTempClassLoader(null);
// 缓存所有bean定义的元数据,不接受后面的改变
beanFactory.freezeConfiguration();
// 实例化所有剩余的(非懒加载)单例bean
beanFactory.preInstantiateSingletons();
}
其中重点看最后一步preInstantiateSingletons方法的实现:
@Override
public void preInstantiateSingletons() throws BeansException {
......
// 迭代一个beanDefinitionNames的副本以允许init方法,这些方法又轮流注册新的bean定义。
// 虽然这可能不是常规工厂引导程序的一部分,但它确实可以正常工作。
List beanNames = new ArrayList<>(this.beanDefinitionNames);
// 触发所有非懒加载单例bean的初始化...
for (String beanName : beanNames) {
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
// 如果不是抽象的bean并且是非懒加载的单例bean,则进行
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
// 判断是否是FactoryBean,如果是则进一步判断是否需要尽早的初始化bean,否则直接初始化bean
if (isFactoryBean(beanName)) {
Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
if (bean instanceof FactoryBean) {
final FactoryBean> factory = (FactoryBean>) bean;
boolean isEagerInit;
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
isEagerInit = AccessController.doPrivileged((PrivilegedAction)
((SmartFactoryBean>) factory)::isEagerInit,
getAccessControlContext());
}
else {
isEagerInit = (factory instanceof SmartFactoryBean &&
((SmartFactoryBean>) factory).isEagerInit());
}
if (isEagerInit) {
getBean(beanName);
}
}
}
else {
getBean(beanName);
}
}
}
// 触发所有可用单例bean的afterSingletonsInstantiated方法回调...
for (String beanName : beanNames) {
Object singletonInstance = getSingleton(beanName);
if (singletonInstance instanceof SmartInitializingSingleton) {
final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction
接下来看getBean(beanName)方法的底层实现,是直接调用doGetBean方法,返回指定bean的实例,该实例可以是共享的或独立的:
protected T doGetBean(final String name, @Nullable final Class requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
// 1. 返回bean名称,必要时删除工厂前缀,并将别名解析为规范名称。
final String beanName = transformedBeanName(name);
Object bean;
// 2. 急切地检查单例缓存以手动地注册单例
Object sharedInstance = getSingleton(beanName);
// 共享的单例bean实例不为空并且args为空
if (sharedInstance != null && args == null) {
if (logger.isTraceEnabled()) {
// 3. 判断该当前bean是否在创建中
if (isSingletonCurrentlyInCreation(beanName)) {
logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
"' that is not fully initialized yet - a consequence of a circular reference");
}
else {
logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
}
}
// 4. 获取给定bean实例的对象,如果是FactoryBean,则为bean实例本身或其创建的对象。
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
else {
// 其它情况暂不做深入研究,感兴趣的读者可以自行阅读AbstractBeanFactory#doGetBean方法源码
......
}
return (T) bean;
}
查看第二点getSingleton方法的实现:
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
Object singletonObject = this.singletonObjects.get(beanName);
// 如果从singletonObjects单例bean缓存中获取key为beanName的单例bean为空并且该单例bean
// 当前在创建中(在整个工厂内)则从早期已实例化的单例bean缓存earlySingletonObjects中
// 检查beanName的单例对象,如果为空则进一步从singletonFactories单例工厂缓存中获取beanName为key
// 的BeanFactory,如果BeanFactory不为空则获取到其管理的单例bean实例并将其缓存
// 到earlySingletonObjects对象上,最后从singletonFactories缓存中移除管理该beanName
// 实例的BeanFactory对象(解决循环引用)
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
ObjectFactory> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
几个重要对象说明:
回到refresh方法的第十二点,最后完成上下文的刷新操作,调用LifecycleProcessor的onRefresh方法并且发布最终的ContextRefreshedEvent事件:
protected void finishRefresh() {
// 清除此资源加载器中的所有资源缓存。
clearResourceCaches();
// 初始化此上下文的生命周期处理器DefaultLifecycleProcessor。
initLifecycleProcessor();
// 调用DefaultLifecycleProcessor的onRefresh方法
getLifecycleProcessor().onRefresh();
// 发布最终的ContextRefreshedEvent事件
publishEvent(new ContextRefreshedEvent(this));
// 如果激活则参与到LiveBeansView MBean中
LiveBeansView.registerApplicationContext(this);
}
子类finishRefresh方法最后启动相应的WebServer并发布事件。
@Override
protected void finishRefresh() {
super.finishRefresh();
WebServer webServer = startWebServer();
if (webServer != null) {
publishEvent(new ServletWebServerInitializedEvent(webServer, this));
}
}
以上就是Spring Boot启动流程源码分析的完整内容,如果有问题欢迎提出!