开启日志
logging:
level:
org.springframework: trace
复制代码
启动项目从日志中依次可以看到这么几个主要类
PropertySourcesPropertyResolver
ClassPathBeanDefinitionScanner
DefaultListableBeanFactory
DockerApplication
SpringApplication
ConfigFileApplicationListener
ConfigServletWebServerApplicationContext
SpringFactoriesLoader
PathMatchingResourcePatternResolver
OnClassCondition
OnWebApplicationCondition
OnBeanCondition
ConfigurationClassBeanDefinitionReader
TomcatServletWebServerFactory
AutowiredAnnotationBeanPostProcessor
CommonAnnotationBeanPostProcessor
ThreadPoolTaskExecutor
RequestMappingHandlerMapping
TomcatWebServer
其基本流程
加载配置文件,装载 bean 对象,初始化请求映射器,启动内嵌的 tomcat。
配置文件加载日志
ConfigFileApplicationListener : Skipped missing config 'file:./config/application.properti
ConfigFileApplicationListener : Skipped missing config 'file:./config/application.xml' (fi
ConfigFileApplicationListener : Skipped missing config 'file:./config/application.yml' (fi
ConfigFileApplicationListener : Skipped missing config 'file:./config/application.yaml' (f
ConfigFileApplicationListener : Skipped missing config 'file:./application.properties' (fi
ConfigFileApplicationListener : Skipped missing config 'file:./application.xml' (file:./ap
ConfigFileApplicationListener : Skipped missing config 'file:./application.yml' (file:./ap
ConfigFileApplicationListener : Skipped missing config 'file:./application.yaml' (file:./a
ConfigFileApplicationListener : Skipped missing config classpath:/config/application.prope
ConfigFileApplicationListener : Skipped missing config classpath:/config/application.xml
ConfigFileApplicationListener : Skipped missing config classpath:/config/application.yml
ConfigFileApplicationListener : Skipped missing config classpath:/config/application.yaml
ConfigFileApplicationListener : Skipped missing config classpath:/application.properties
ConfigFileApplicationListener : Skipped missing config classpath:/application.xml
ConfigFileApplicationListener : Loaded config file 'file:.../target/classes/application.yml' (classpath:/application.yml)
ConfigFileApplicationListener : Skipped missing config classpath:/application.yaml
复制代码
日志的加载顺序
从日志中可以看出日志的加载顺序
run 的过程
SpringApplication.run 的过程构建了 ApplicationContext
public ConfigurableApplicationContext run(String... args) {
// 耗时统计
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
configureHeadlessProperty();
// application监听
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
// 加载环境变量 配置文件
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
configureIgnoreBeanInfo(environment);
Banner printedBanner = printBanner(environment);
context = createApplicationContext();
exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
// 准备上下文
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
// 刷新上下文
refreshContext(context);
afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
}
// 程序已启动
listeners.started(context);
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}
try {
// 程序正在运行
listeners.running(context);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
return context;
}
复制代码
AnnotationConfigServletWebServerApplicationContext 继承关系
AbstractApplicationContext (org.springframework.context.support)
|--GenericApplicationContext (org.springframework.context.support)
|--|--GenericWebApplicationContext (org.springframework.web.context.support)
|--|--|--ServletWebServerApplicationContext (org.springframework.boot.web.servlet.context)
|--|--|--|--AnnotationConfigServletWebServerApplicationContext (org.springframework.boot.web.servlet.context)
refreshBean 使用 DefaultListableBeanFactory 进行加载 bean
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
initMessageSource();
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
onRefresh();
// Check for listener beans and register them.
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
finishRefresh();
}
...
}
复制代码
ApplicationListener 与 ApplicationEvent
ApplicationEvent 部分继承关系
ApplicationEvent (org.springframework.context)
|--SpringApplicationEvent (org.springframework.boot.context.event)
|--|--ApplicationEnvironmentPreparedEvent
|--|--ApplicationContextInitializedEvent (org.springframework.boot.context.event)
|--|--|--ApplicationEnvironmentPreparedEvent (org.springframework.boot.context.event)
|--|--|--ApplicationPreparedEvent (org.springframework.boot.context.event)
|--|--|--ApplicationStartedEvent (org.springframework.boot.context.event)
|--|--|--ApplicationReadyEvent (org.springframework.boot.context.event)
|--|--|--ApplicationFailedEvent (org.springframework.boot.context.event)
|--ApplicationContextEvent (org.springframework.context.event)
|--|--ContextClosedEvent (org.springframework.context.event)
|--|--ContextRefreshedEvent (org.springframework.context.event)
|--|--ContextStoppedEvent (org.springframework.context.event)
|--|--ContextStartedEvent (org.springframework.context.event)
|-- ...
SimpleApplicationEventMulticaster 用于管理 ApplicationListener 与 ApplicationEvent,这有点像 java swing 中的事件处理,如鼠标点击发送一个事件,然后有一个 listener 处理这个事件。
multicastEvent 用于触发 listener 与 envent 事件,最终调用 listener 的 onApplicationEvent 方法。
如 ConfigFileApplicationListener 处理 ApplicationEnvironmentPreparedEvent 事件。
LoggingApplicationListener 处理 ApplicationEnvironmentPreparedEvent 事件。
整个启动过程 listener 开始启动==>启动完成==>正在运行
listeners.starting();
...
listeners.started(context);
...
listeners.running(context);
复制代码
listeners 保存了已注册的 SpringApplicationRunListener 列表,listeners 的处理即循环调用每个 listener 的处理。
SpringApplicationRunListener 的实现类 EventPublishingRunListener。
Listener 通过 SimpleApplicationEventMulticaster#multicastEvent 广播事件,doInvokeListener 调用事件处理,监听 listener 调用 onApplicationEvent 进行处理事件。
listeners.started(context) 的事件传播是通过 AbstractApplicationContext#publishEvent 进行 Event 加工及关联较早的事件,再通过 SimpleApplicationEventMulticaster 进行广播事件,同时事件向父类传播。
来看下整个启动过程的监听内容
public interface SpringApplicationRunListener {
/**
* 正在启动
* Called immediately when the run method has first started. Can be used for very
* early initialization.
*/
default void starting() {
}
/**
* 环境准备完成
* Called once the environment has been prepared, but before the
* {@link ApplicationContext} has been created.
* @param environment the environment
*/
default void environmentPrepared(ConfigurableEnvironment environment) {
}
/**
* context准备完成
* Called once the {@link ApplicationContext} has been created and prepared, but
* before sources have been loaded.
* @param context the application context
*/
default void contextPrepared(ConfigurableApplicationContext context) {
}
/**
* context加载完成
* Called once the application context has been loaded but before it has been
* refreshed.
* @param context the application context
*/
default void contextLoaded(ConfigurableApplicationContext context) {
}
/**
* 启动完成
* The context has been refreshed and the application has started but
* {@link CommandLineRunner CommandLineRunners} and {@link ApplicationRunner
* ApplicationRunners} have not been called.
* @param context the application context.
* @since 2.0.0
*/
default void started(ConfigurableApplicationContext context) {
}
/**
* 正在运行
* Called immediately before the run method finishes, when the application context has
* been refreshed and all {@link CommandLineRunner CommandLineRunners} and
* {@link ApplicationRunner ApplicationRunners} have been called.
* @param context the application context.
* @since 2.0.0
*/
default void running(ConfigurableApplicationContext context) {
}
/**
* 失败
* Called when a failure occurs when running the application.
* @param context the application context or {@code null} if a failure occurred before
* the context was created
* @param exception the failure
* @since 2.0.0
*/
default void failed(ConfigurableApplicationContext context, Throwable exception) {
}
}
复制代码
总结
SpirngApplication 在启动时通过 listener 处理启动过程的一些事件 event。加载上下文过程先获取环境变量配置文件,创建初始 context ,prepareContext 阶段将 context、environment 与 listener 绑定,处理后续的 event,refreshContext 阶段进行 bean 加载及 postProcessors 处理,自动装配加载,条件配置 bean 的加载,最终生成装配完 bean 的上下文 ApplicationContext,最后发布程序启动完成、正在运行事件,并有 listener 进行处理,至此程序启动完成。
今天暂且写到这,有空继续研究。
评论