开启日志
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.propertiConfigFileApplicationListener : Skipped missing config 'file:./config/application.xml' (fiConfigFileApplicationListener : Skipped missing config 'file:./config/application.yml' (fiConfigFileApplicationListener : Skipped missing config 'file:./config/application.yaml' (fConfigFileApplicationListener : Skipped missing config 'file:./application.properties' (fiConfigFileApplicationListener : Skipped missing config 'file:./application.xml' (file:./apConfigFileApplicationListener : Skipped missing config 'file:./application.yml' (file:./apConfigFileApplicationListener : Skipped missing config 'file:./application.yaml' (file:./aConfigFileApplicationListener : Skipped missing config classpath:/config/application.propeConfigFileApplicationListener : 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 进行处理,至此程序启动完成。
今天暂且写到这,有空继续研究。
评论