SpringBoot 从入门到光头 —— 第十章 原理解析
1. SpringBoot 原理
Spring 原理、Spring 注解、SpringMVC 原理、自动配置原理、SpringBoot 原理
2. SpringBoot 自动过程
创建 SpringApplication
- 保存一些信息
- 判定当前应用的类型
ClassUtils
,一般情况下是Servlet
bootstrappers
:初始启动引导器(List<Bootstrapper>
):去spring.factories
文件中查找org.springframework.boot.Bootstrapper
- 查找
ApplicationContextInitializer
:去spring.factories
中查找ApplicationContextInitializer
List<ApplicationContextInitializer<?>> initializers
- 查找
ApplicationListener
:应用监听器,去spring.factories
中查找ApplicationListener
List<ApplicationListener<?>> listeners
运行 SpringApplication
StopWatch
记录应用的启动时间
创建引导上下文(Context 环境)
createBootstrapContext()
org.springframework.boot.BootstrapRegistryInitializer
/** * Callback interface that can be used to initialize a {@link BootstrapRegistry} before it * is used. * * @author Phillip Webb * @since 2.4.5 * @see SpringApplication#addBootstrapRegistryInitializer(BootstrapRegistryInitializer) * @see BootstrapRegistry */ @FunctionalInterface public interface BootstrapRegistryInitializer { /** * Initialize the given {@link BootstrapRegistry} with any required registrations. * @param registry the registry to initialize */ void initialize(BootstrapRegistry registry); }
- 获取到所有之前的
bootstrappers
挨个执行intitialize()
方法来完成对引导启动器上下文环境设置
- 获取到所有之前的
让当前应用进入
headless
模式,java.awt.headless
获取所有
RunListener
(运行监听器)【为了方便所有 Listener 进行事件感知】getSpringFactoriesInstances
在spring.factories
找SpringApplicationRunListener
遍历
SpringApplicationRunListener
调用starting
方法- 相当于通知所有感兴趣系统正在启动过程的人,项目正在
starting
- 相当于通知所有感兴趣系统正在启动过程的人,项目正在
保存命令行参数
ApplicationArguments
准备环境
prepareEnvironment()
- 返回或者创建基础环境信息对象,
StandardServletEnvironment
- 配置环境信息对象
- 读取所有的配置源的配置属性值
- 绑定环境信息
- 监听器调用
listener.environmentPrepared()
,通知所有的监听器当前环境准备完成
- 返回或者创建基础环境信息对象,
创建 IOC 容器(
createApplicationContext()
)- 根据项目类型(Servlet)创建容器
- 在当前会话中创建
AnnotationConfigServletWebServerApplicationContext
准备
ApplicationContext
IOC 容器的基本信息prepareContext()
保存环境信息
IOC 容器的后置处理流程
应用初始化器:
applyInitializers
遍历所有的
ApplicationContextInitializer
调用initialize()
来对 IOC 容器进行初始化扩展功能遍历所有的 Listener 调用
contextPrepared()
,EventPublishRunListenr
,通知所有的监听器contextPrepared()
所有的监听器调用
contextLoaded()
通知所有的监听器contextLoaded()
刷新 IOC 容器
refreshContext()
- 创建容器中的所有组件(Spring 注解)
容器刷新完成后的工作:
afterRefresh()
所有监听器调用
listeners.started(context)
,通知所有的监听器started
调用所有
runners
:callRunners()
- 获取容器中的
ApplicationRunner
- 获取容器中的
CommandLineRunner
- 获取容器中的
- 获取容器中的
合并所有
runner
并且按照@Order
进行排序遍历所有的
runner
,调用run()
方法
org.springframework.boot.ApplicationRunner
/** * Interface used to indicate that a bean should <em>run</em> when it is contained within * a {@link SpringApplication}. Multiple {@link ApplicationRunner} beans can be defined * within the same application context and can be ordered using the {@link Ordered} * interface or {@link Order @Order} annotation. * * @author Phillip Webb * @since 1.3.0 * @see CommandLineRunner */ @FunctionalInterface public interface ApplicationRunner { /** * Callback used to run the bean. * @param args incoming application arguments * @throws Exception on error */ void run(ApplicationArguments args) throws Exception; }
org.springframework.boot.CommandLineRunner
/** * Interface used to indicate that a bean should <em>run</em> when it is contained within * a {@link SpringApplication}. Multiple {@link CommandLineRunner} beans can be defined * within the same application context and can be ordered using the {@link Ordered} * interface or {@link Order @Order} annotation. * <p> * If you need access to {@link ApplicationArguments} instead of the raw String array * consider using {@link ApplicationRunner}. * * @author Dave Syer * @since 1.0.0 * @see ApplicationRunner */ @FunctionalInterface public interface CommandLineRunner { /** * Callback used to run the bean. * @param args incoming main method arguments * @throws Exception on error */ void run(String... args) throws Exception; }
如果以上有异常:
- 调用 Listener 的
failed()
方法
- 调用 Listener 的
调用所有监听器的
running()
方法listeners.running(context)
,通知所有的监听器running
running()
如果有问题,继续通知failed
,调用所有 Listener 的failed()
方法,通知所有的监听器failed
3. Application Events 和 Liateners
ApplicationContextInitializer
ApplicationListener
SpringAppliactionRunListener
示例代码:
com.gregperlinli.boot.listener.MyApplicationContextInitializer
/**
* @author gregPerlinLi
* @since 2021-11-29
*/
public class MyApplicationContextInitializer implements ApplicationContextInitializer {
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
System.out.println("MyApplicationContextInitializer.initialize ... ");
}
}
com.gregperlinli.boot.listener.MyApplicationListener
/**
* @author gregPerlinLi
* @since 2021-11-29
*/
public class MyApplicationListener implements ApplicationListener {
@Override
public void onApplicationEvent(ApplicationEvent event) {
System.out.println("MyApplicationListener.onApplicationEvent ... ");
}
}
com.gregperlinli.boot.listener.MySpringApplicationRunListener
/**
* @author gregPerlinLi
* @since 2021-11-29
*/
public class MySpringApplicationRunListener implements SpringApplicationRunListener {
private SpringApplication application;
public MySpringApplicationRunListener(SpringApplication application, String[] args) {
this.application = application;
}
@Override
public void starting(ConfigurableBootstrapContext bootstrapContext) {
System.out.println("MySpringApplicationRunListener.starting ... ");
}
@Override
public void environmentPrepared(ConfigurableBootstrapContext bootstrapContext, ConfigurableEnvironment environment) {
System.out.println("MySpringApplicationRunListener.environmentPrepared ... ");
}
@Override
public void contextPrepared(ConfigurableApplicationContext context) {
System.out.println("MySpringApplicationRunListener.contextPrepared ... ");
}
@Override
public void contextLoaded(ConfigurableApplicationContext context) {
System.out.println("MySpringApplicationRunListener.contextLoaded ... ");
}
@Override
public void started(ConfigurableApplicationContext context, Duration timeTaken) {
System.out.println("MySpringApplicationRunListener.started ... ");
}
@Override
public void ready(ConfigurableApplicationContext context, Duration timeTaken) {
System.out.println("MySpringApplicationRunListener.ready ... ");
}
@Override
public void failed(ConfigurableApplicationContext context, Throwable exception) {
System.out.println("MySpringApplicationRunListener.failed ... ");
}
}
spring.factories
org.springframework.context.ApplicationContextInitializer=\
com.gregperlinli.boot.listener.MyApplicationContextInitializer
org.springframework.context.ApplicationListener=\
com.gregperlinli.boot.listener.MyApplicationListener
org.springframework.boot.SpringApplicationRunListener=\
com.gregperlinli.boot.listener.MySpringApplicationRunListener
4. ApplicationRunner
和 CommandLineRunner
示例代码:
com.gregperlinli.boot.listener.MyApplicationRunner
/**
* @author gregPerlinLi
* @since 2021-11-29
*/
@Order(1)
@Component
public class MyApplicationRunner implements ApplicationRunner {
@Override
public void run(ApplicationArguments args) throws Exception {
System.out.println("MyApplicationRunner.run ... ");
}
}
com.gregperlinli.boot.listener.MyCommandLineRunner
/**
* Application startup does a one-time thing
*
* @author gregPerlinLi
* @since 2021-11-29
*/
@Order(2)
@Component
public class MyCommandLineRunner implements CommandLineRunner {
@Override
public void run(String... args) throws Exception {
System.out.println("MyCommandLineRunner.run ... ");
}
}