SpringBoot 启动流程
写在前面的话用SpringBoot 已经有很长一段时间了,在系统中架构中也使用了SpringBoot 的一些加载机制。比如:在系统启动前后执行数据库更新文件;自定义事件后在某个时机去执行具体的业务;再有就是修改一些自动配置类等。但都没有对SpingBoot 的启动流程做总结,那么今天就来总结一下。此篇源码基于版本:spring-boot-starter-parent:2.3.4.RELEASE启动
一、写在前面的话
用SpringBoot 已经有很长一段时间了,在工作中也使用了SpringBoot 的一些加载机制。比如:在系统启动前后执行数据库更新文件;自定义事件后在某个时机去执行具体的业务;再有就是修改一些自动配置类等。但都没有对SpingBoot 的启动流程做总结,那么今天就来总结一下。此篇源码基于版本:spring-boot-starter-parent:2.3.4.RELEASE
二、启动流程详解
1、关键注解:@SpringBootApplication
众所周知,在 SpringBoot
启动类上都少不了此注解:
@SpringBootApplication
public class PromoteApplication {
public static void main(String[] args) {
SpringApplication.run(PromoteApplication.class, args);
}
}
查看注解源码:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
@AliasFor(annotation = EnableAutoConfiguration.class)
Class<?>[] exclude() default {};
@AliasFor(annotation = EnableAutoConfiguration.class)
String[] excludeName() default {};
@AliasFor(annotation = ComponentScan.class, attribute = "basePackages")
String[] scanBasePackages() default {};
@AliasFor(annotation = ComponentScan.class, attribute = "basePackageClasses")
Class<?>[] scanBasePackageClasses() default {};
@AliasFor(annotation = ComponentScan.class, attribute = "nameGenerator")
Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;
@AliasFor(annotation = Configuration.class)
boolean proxyBeanMethods() default true;
其核心使用了@SpringBootConfiguration
和 @EnableAutoConfiguration
,前者的作用类似于 @Configuration
表明是一个Java 配置类。而@EnableAutoConfiguration
则是将所有符合配置条件的 Bean 都加载到 IOC 容器中。查看其源码:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
Class<?>[] exclude() default {};
String[] excludeName() default {};
}
其核心类为:AutoConfigurationImportSelector
,类图如下:
程序通过执行了 AutoConfigurationImportSelector.AutoConfigurationGroup.selectImports()
获取到符合条件的配置类,如下源码:
@Override
public void process(AnnotationMetadata annotationMetadata, DeferredImportSelector deferredImportSelector) {
Assert.state(deferredImportSelector instanceof AutoConfigurationImportSelector,
() -> String.format("Only %s implementations are supported, got %s",
AutoConfigurationImportSelector.class.getSimpleName(),
deferredImportSelector.getClass().getName()));
//根据 deferredImportSelector 获取自动配置entry:
AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector)
.getAutoConfigurationEntry(annotationMetadata);
this.autoConfigurationEntries.add(autoConfigurationEntry);
for (String importClassName : autoConfigurationEntry.getConfigurations()) {
this.entries.putIfAbsent(importClassName, annotationMetadata);
}
}
AutoConfigurationImportSelector.getAutoConfigurationEntry
的源码如下:
protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
}
//获取 @EnableAutoConfiguration 中的属性(exclude 和 excludeName)
AnnotationAttributes attributes = getAttributes(annotationMetadata);
//从META-INF/spring.factories 中获取自动配置类
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
//删除重复的配置
configurations = removeDuplicates(configurations);
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
checkExcludedClasses(configurations, exclusions);
// 移除所有在 exclude 和 excludeName 定义的类
configurations.removeAll(exclusions);
configurations = getConfigurationClassFilter().filter(configurations);
fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationEntry(configurations, exclusions);
}
getCandidateConfigurations()
的源码如下, 总结起来就是通过加载 spring.factories
文件, 找出对应的配置类:
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
getBeanClassLoader());
Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you "
+ "are using a custom packaging, make sure that file is correct.");
return configurations;
}
再回到 AutoConfigurationImportSelector.AutoConfigurationGroup.process()
中,一共过滤出了31个自动配置类:
执行完上述方法后,进行当前类的selectImports()
:
2.SpringApplication.run()
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
configureHeadlessProperty();
//获取监听器
SpringApplicationRunListeners listeners = getRunListeners(args); //(1)
listeners.starting(); //(2)
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);// (3)
configureIgnoreBeanInfo(environment);
Banner printedBanner = printBanner(environment);
context = createApplicationContext(); // (4)
exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
new Class[]{ConfigurableApplicationContext.class}, context);
prepareContext(context, environment, listeners, applicationArguments, printedBanner); // (5)
refreshContext(context); // (6)
afterRefresh(context, applicationArguments); // (7)
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
}
listeners.started(context); // (8)
callRunners(context, applicationArguments); // (9)
} catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}
try {
listeners.running(context); // (10)
} catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
return context;
}
以上执行流程可以总结为:
1)getRunListeners
源码如下:
SpringApplicationRunListeners listeners = getRunListeners(args);
private SpringApplicationRunListeners getRunListeners(String[] args) {
Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
// 此处获取SpringApplicationRunListener的实现类:EventPublishingRunListener,并返回实例。
return new SpringApplicationRunListeners(logger,
getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));
}
2)listeners.starting
源码如下:
listeners.starting();
// SpringApplicationRunListeners.starting():
void starting() {
for (SpringApplicationRunListener listener : this.listeners) {
listener.starting();
}
}
// EventPublishingRunListener.starting(),发布 ApplicationStartingEvent
@Override
public void starting() {
this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args));
}
3)prepareEnvironment
准备环境:prepareEnvironment(listeners, applicationArguments);
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments) {
// 创建并配置环境
ConfigurableEnvironment environment = getOrCreateEnvironment();
configureEnvironment(environment, applicationArguments.getSourceArgs());
ConfigurationPropertySources.attach(environment);
// 调用 EventPublishingRunListener.environmentPrepared() 发布事件:ApplicationEnvironmentPreparedEvent
listeners.environmentPrepared(environment);
bindToSpringApplication(environment);
if (!this.isCustomEnvironment) {
environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,
deduceEnvironmentClass());
}
ConfigurationPropertySources.attach(environment);
return environment;
}
4)createApplicationContext
创建一个 ConfigurableApplicationContext
子类并且实例化:
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);
}
DEFAULT_SERVLET_WEB_CONTEXT_CLASS
对应的类:org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext
, 类图为:
DEFAULT_REACTIVE_WEB_CONTEXT_CLASS
对应的类:org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext
,类图为:DEFAULT_CONTEXT_CLASS
对应的类:org.springframework.context.annotation.AnnotationConfigApplicationContext
,类图为:
5)prepareContext
准备上下文,源码如下:
private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
context.setEnvironment(environment);
// 注册单例 beanNameGenerator,把ResourceLoader设置进应用上下文
postProcessApplicationContext(context);
// 执行初始化器
applyInitializers(context);
// 1) 发布事件:ApplicationPreparedEvent。看具体下文解释
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);
}
if (this.lazyInitialization) {
context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
}
// 载入资源
Set<Object> sources = getAllSources();
Assert.notEmpty(sources, "Sources must not be empty");
load(context, sources.toArray(new Object[0]));
listeners.contextLoaded(context);
}
listeners.contextPrepared(context);
//org.springframework.boot.SpringApplicationRunListeners.contextPrepared()
void contextPrepared(ConfigurableApplicationContext context) {
for (SpringApplicationRunListener listener : this.listeners) {
listener.contextPrepared(context);
}
}
// org.springframework.boot.context.event.EventPublishingRunListener.contextPrepared()
@Override
public void contextPrepared(ConfigurableApplicationContext context) {
this.initialMulticaster.multicastEvent(new ApplicationContextInitializedEvent(this.application, this.args, context));
}
6)refreshContext
刷新上下文:
private void refreshContext(ConfigurableApplicationContext context) {
refresh(context);
if (this.registerShutdownHook) {
try {
context.registerShutdownHook();
}
catch (AccessControlException ex) {
// Not allowed in some environments.
}
}
}
protected void refresh(ApplicationContext applicationContext) {
Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);
((AbstractApplicationContext) applicationContext).refresh();
}
//org.springframework.context.support.AbstractApplicationContext#refresh
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 为上下文刷新做准备,设置启动日期和执行标志,以及对属性资源进行初始化操作
prepareRefresh();
// 告诉子类,刷新内部Bean 工厂。通常留给子类自己实现 refreshBeanFactory()
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 配置 BeanFactory 的属性,例如:类加载器或后置处理器
prepareBeanFactory(beanFactory);
try {
//允许在上下文子类中对Bean 进行后置处理(修改Bean信息等)
postProcessBeanFactory(beanFactory);
// 在上下文中调用注册为Bean的工厂处理器
invokeBeanFactoryPostProcessors(beanFactory);
// 注册拦截bean创建的bean处理器。
registerBeanPostProcessors(beanFactory);
// 初始化上下文的消息源
initMessageSource();
// 初始化应用事件广播器:ApplicationEventMulticaster
initApplicationEventMulticaster();
// 初始化其它特殊的Bean
onRefresh();
// 检查并向容器注册监听器
registerListeners();
//实例化所有剩余的(非lazy init)单例Bean。
finishBeanFactoryInitialization(beanFactory);
// 结束上下文刷新,发布事件:ContextRefreshedEvent
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// 销毁已经创建的单例Bean,以避免资源占用
destroyBeans();
// 取消上下文刷新,重置 active 标志位
cancelRefresh(ex);
throw ex;
}
finally {
// 重置Spring 核心缓存,特别是ReflectionUtils、AnnotationUtils、ResolvableType和CachedIntrospectionResults缓存。
resetCommonCaches();
}
}
}
7)afterRefresh
空方法,在刷新完上下文后调用
protected void afterRefresh(ConfigurableApplicationContext context, ApplicationArguments args) {
}
8)listeners.started
实际是调用 org.springframework.boot.SpringApplicationRunListeners.started()
void started(ConfigurableApplicationContext context) {
for (SpringApplicationRunListener listener : this.listeners) {
listener.started(context);
}
}
再调用:org.springframework.boot.context.event.EventPublishingRunListener.started()
,发布事件:ApplicationStartedEvent
@Override
public void started(ConfigurableApplicationContext context) {
context.publishEvent(new ApplicationStartedEvent(this.application, this.args, context));
}
9)callRunners
执行 ApplicationRunner
和 CommandLineRunner
的实现类的 run()
可以利用两个类做系统更新的一些操作。
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);
}
}
}
private void callRunner(ApplicationRunner runner, ApplicationArguments args) {
try {
(runner).run(args);
}
catch (Exception ex) {
throw new IllegalStateException("Failed to execute ApplicationRunner", ex);
}
}
private void callRunner(CommandLineRunner runner, ApplicationArguments args) {
try {
(runner).run(args.getSourceArgs());
}
catch (Exception ex) {
throw new IllegalStateException("Failed to execute CommandLineRunner", ex);
}
}
10)listeners.running
实际调用 :org.springframework.boot.SpringApplicationRunListeners.running()
void running(ConfigurableApplicationContext context) {
for (SpringApplicationRunListener listener : this.listeners) {
listener.running(context);
}
}
再调用 org.springframework.boot.context.event.EventPublishingRunListener.running()
,发布事件:ApplicationReadyEvent
@Override
public void running(ConfigurableApplicationContext context) {
context.publishEvent(new ApplicationReadyEvent(this.application, this.args, context));
}
三、总结
从上述的流程图中可以看到,有部分执行过程中涉及到不同的事件发布。那么查看 org.springframework.boot.context.event.SpringApplicationEvent
的实现类,上述涉及到 6 种不同的事件:
Spring 事件监听使用了观察者模式。在此有三种角色:事件发布者,事件,事件对应的监听器。具体的执行原理如下:
更多推荐
所有评论(0)