一、启动流程
1.创建SpringApplication对象
//通过调用自身的构造方法创建对象
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources){
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
//保存配置类
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
//当前web应用的类型
this.webApplicationType = WebApplicationType.deduceFromClasspath();
//从类路径下找到META-INF/spring.factories配置的所有ApplicationContextInitializer;并保存起来
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
//从类路径下找到META-INF/spring.factories配置的所有ApplicationListener;并保存起来
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
//从多个配置类中找到有main方法的配置类
this.mainApplicationClass = deduceMainApplicationClass();
}
2.运行run方法
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
//awt相关配置
configureHeadlessProperty();
//获取SpringApplicationRunListeners:从类路径下找到META-INF/spring.factories配置的所有SpringApplicationRunListener
SpringApplicationRunListeners listeners = getRunListeners(args);
//回调所有的SpringApplicationRunListener的starting方法
listeners.starting();
try {
//封装命令行参数
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
//准备并配置环境,创建环境完成后回调所有SpringApplicationRunListener的environmentPrepared方法
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
//配置忽略bean信息
configureIgnoreBeanInfo(environment);
//在控制台打印图案
Banner printedBanner = printBanner(environment);
//创建applicationContext。根据当前环境类型,来判断创建ioc容器的类型是普通的ioc还是web的ioc,通过反射完成创建
context = createApplicationContext();
//出现异常后做异常分析报告
exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
//准备上下文环境,将environment保存到ioc中
//调用applyInitializers(context),回调所有ApplicationContextInitializer的initialize方法
//调用listeners.contextPrepared(context);,回调所有SpringApplicationRunListener的contextPrepared方法
//最后调用listeners.contextLoaded(context);,回调所有SpringApplicationRunListener的contextLoaded方法
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
//刷新容器,ioc容器初始化完成。
//扫描,创建,加载所有组件的地方
refreshContext(context);
//2.x版本为空方法
afterRefresh(context, applicationArguments);
stopWatch.stop();
//打印启动日志
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
}
//回调所有ApplicationListener的started方法
listeners.started(context);
//从ioc容器中获取所有的ApplicationRunner和CommandLineRunner并回调,ApplicationRunner先回调,CommandLineRunner后回调
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}
try {
//回调所有SpringApplicationRunListener的running方法
listeners.running(context);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
//启动完成后返回ioc容器
return context;
}
3. 事件监听机制
由上面可知,在启动过程中,存在的几个事件回调机制
-
ApplicationContextInitializer:在准备上下文环境的时候会调用该接口实现类的initialize方法。通常在需要对应用程序上下文进行一些程序初始化的Web应用程序中使用。
-
SpringApplicationRunListener:监听SpringApplication调用run方法中执行的一些关键方法
-
ApplicationRunner:实现了该接口的类,会在启动过程中调用类的run方法
-
CommandLineRunner:与ApplicationRunner基本相同,但后于ApplicationRunner调用run方法。
配置
ApplicationContextInitializer与SpringApplicationRunListener需要在META-INF/spring.factories中进行配置
ApplicationRunner与CommandLineRunner只需要加入到IOC容器中便可
二、自定义starter
1.如何编写自动配置?我们可以先看看一些自动配置类都用了什么
@Configuration //指定这个类是配置类
@ConditionalOnXXX //在指定条件成立的情况下自动配置类生效
@AutoConfigureAfter //指定自动配置类的顺序
@Bean //给容器中添加组件
@ConfigurationProperties//结合相关xxxProperties类来绑定相关的配置
@EnableConfigurationProperties //让xxxProperties生效加入到容器中
要想 自动配置类能够在启动的时候就加载。将其配置在META-INF/spring.factories中
例:
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
其中第一行是接口,\代表换行,其后跟着的是配置类
2.模式
启动器只用来做依赖导入
专门写一个自动配置类
启动器依赖自动配置;使用只需引入启动器(starter)
过程如下:
- 创建两个项目,一个maven项目,一个springboot项目
- maven项目中什么都不写,单纯地添加另一个项目的坐标。这个maven项目就作为启动器,在添加启动器的依赖的时候,就会将自动配置类也添加进来。
- 在springboot项目中,创建一个类xxxProperties使用@ConfigurationProperties注解,来绑定相关的配置属性。
- 使用@Configuration 创建一个配置类,@EnableConfigurationProperties(xxxProperties.class)。可根据需求添加注解,在配置类中添加组件。
- 将配置类在META-INF/spring.factories中进行配置