写点什么

SpringApplication 启动 run 了啥

用户头像
Rubble
关注
发布于: 17 小时前

开启日志

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        
复制代码

日志的加载顺序

从日志中可以看出日志的加载顺序


  • file > classpath

  • config > 当前目录.

  • Properties > xml > ym l> 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 进行处理,至此程序启动完成。


今天暂且写到这,有空继续研究。

用户头像

Rubble

关注

还未添加个人签名 2021.06.01 加入

还未添加个人简介

评论

发布
暂无评论
SpringApplication启动run了啥