进入SpringApplication.run(HelloWorldMainApplication.class, args);
方法:
SpringApplication
构造器:
引入的依赖中spring-boot-starter-web
的配置文件又会引入Tomcat和spring-webmvc.spring-webmvc中存在DispatcherServlet
这个类,也就是SpringMVC的核心Servlet,通过类加载能加载DispatcherServlet这个类,那么应用类型自然就是WebApplicationType.SERVLET
。
函数getSpringFactoriesInstances( ApplicationContextInitializer.class)
loadFactoryNames
函数源码:
以spring-boot-autoconfigure
这个包为例,它的META-INF/spring.factories
部分定义如下:
SharedMetadataReaderFactoryContextInitializer
和AutoConfigurationReportLoggingInitializer
这两个类名被读取出来,然后放入到Set
集合(保存的是要加载的类名)中,然后开始实例化操作:
初始化器就是org.springframework.context.ApplicationContextInitializer
的实现类,这个接口的定义为:
在Web应用中,注册Property Sources或者是激活Profiles。Property Sources就是配置文件;Profiles是Spring为了在不同环境下(如DEV、TEST、PRODUCTION等),加载不同的配置项而抽象出来的一个实体。
函数getSpringFactoriesInstances
的实现:
spring-boot-autoconfigure
这个包中的spring.factories
中的Key-Value
为:
这10个监听器会贯穿SpringBoot整个生命周期。到此为止,对于SpringApplication实例的初始化过程就结束了。
SpringApplicationRunListeners
以及参数来准备环境
从META-INF/spring.factories
中读取Key为org.springframework.boot.SpringApplicationRunListener
的Values:
在函数getSpringFactoriesInstances
中利用反射获取实例时会触发EventPublishingRunListener
的构造函数,该函数的具体实现为:
添加广播器的源码:
该方法定义在SimpleApplicationEventMulticaster
父类AbstractApplicationEventMulticaster
中。
综上我们可以看到:EventPublishingRunListener
中有一个广播器SimpleApplicationEventMulticaster
,广播器SimpleApplicationEventMulticaster
中又存放所有的监听器。
通过getRunListeners
方法获取的监听器为EventPublishingRunListener
,该监听器是启动事件发布监听器,主要用来发布启动事件。
首先来看一下SpringApplicationRunListener
这个接口:
SpringBoot启动时第一个启动事件listeners.starting()
:
继续看SimpleApplicationEventMulticaster
的核心方法:
这里有四种监听器:
以SpringBoot的日志监听器为例,核心代码:因为该事件类型为ApplicationEvent
,所以会执行onApplicationStartedEvent((ApplicationStartedEvent) event);
。SpringBoot会在运行过程中的不同阶段,发送各种事件,来执行对应监听器的对应方法。
具体实现:
函数listeners.environmentPrepared(environment);
,这里是第二次发布事件,根据事件类型获取到的监听器为:
其中的ConfigFileApplicationListener
非常核心,主要用来处理项目配置,项目中的properties
和yml
文件都是其内部类所加载。
首先还是会读spring.factories
文件,List
获取的处理类有以下四种:
在执行完上述三个监听器流程后,ConfigFileApplicationListener
会执行该类本身的逻辑,由其内部类Loader
加载项目制定路径下的配置文件:
到此为止,项目的变量配置已全部加载完毕。
一共有6个配置文件,取值顺序由上到下。也就是说前面的配置变量会覆盖后面同名的配置变量。
首先需要了解一下什么是容器?
Spring容器是Spring框架的核心,是用来管理对象的,容器创建对象,把它们连接在一起,配置他们,并管理他们的整个生命周期,从创建到销毁。
在java项目中,使用了org.springframework.context.ApplicationContext
接口的实现类;在web项目中,使用了spring.xml—Spring的配置文件(在xml中配置了一系列我们需要的bean,配置之后Spring就会按照我们配置的东西进行解析,从而得到我们需要的值)。
Spring提供了两种不同类型的容器:
BeanFactory容器:它是最简单的容器
ApplicationContext:该容器继承自BeanFactory,包括BeanFactory容器的所有功能。
这一步主要是在容器刷新之前的准备动作,包含一个非常关键的操作:将启动类注入容器,为后续开启自动化配置奠定基础。
具体实现:
调用初始化器:
我们也可以自定义初始化器,并实现initialize
方法,然后放入METAINF/spring.factories
配置文件中Key为:org.springframework.context.ApplicationContextInitializer
的value中,这里我们自定义的初始化器就会被调用,是项目初始化的一种方式。
加载启动指定类
在创建SpringApplication
实例中,先将HelloWorldMainApplication.class
存储在this.primarySources
属性中,现在就是用这个属性的时候了,getAllSources()
方法的具体实现:
函数load(context, sources.toArray(new Object[0]));
的具体实现:
通知监听器,容器已准备就绪:
主要还是针对一些日志等监听器的响应处理。
执行到这里,springBoot相关的处理工作已经结束,接下来的工作就交给Spring了,接下来我们来看一下refreshContext(context);
函数,该方法是实现IOC和AOP的关键。
扩展接口,设计模式中的模板方法,默认为空实现。如果有自定义需求,可以重写该方法,比如打印一些启动结束log,或者一些其他后置处理。
这里是在Spring容器中发布事件,并不是在SpringApplication中发布事件,和前面的starting是不同的,前面的starting是直接向SpringApplication中的11个监听器发布启动事件。
函数callRunners(context, applicationArguments);
源码:
如果是CommandLineRunner的话,执行如下代码:
我们也可以自定义一些ApplicationRunner或者CommandLineRunner,实现其run方法,并注入到Spring容器中,在SpringBoot启动完成之后,会执行所有的runnner的run方法。
感谢并参考:
https://www.cnblogs.com/java-chen-hao/p/11829344.html