034:SpringBoot配置解析源码分析
1 SpringBoot启动流程总结01
课题内容:
- SpringBoot源码分析之配置文件解析原理
- SpringBoot启动流程整体源码总结
- Spring源码总结之Spring体系面试题复习
总结SpringBoot启动流程
核心分为两个步骤;
- 创建 SpringApplication对象
- 调用SpringApplication run 实现启动,同时返回当前的容器上下文
分析流程:
- 创建SpringApplication对象 SpringBoot容器初始化操作;
- 获取当前应用启动类型 原理:判断当前classpath是否有加载servlet类,如果有,返回Servlet web启动方式;
webApplicationType 分为三种类型:
1.响应式启动 (Spring5新特性)
2.None 不会嵌入web容器启动 (将SpringBoot项目放入外部服务器运行)
3.SERVLET 基于Web容器启动 - setInitializers 读取SpringBoot包下面的META-INF/spring.factories获取到对应ApplicationContextInitializer 装配到集合中;
- setListeners读取SpringBoot包下面的META-INF/spring.factories获取到对应ApplicationListener装配到集合中;
- mainApplicationClass 获取当前运行的主函数;
- 调用SpringApplication run方法实现启动;
- StopWatch stopWatch = new StopWatch(); 记录SpringBoot项目启动时间
2 SpringBoot自定义外部扩展文件01
自定义加载配置文件
引入依赖
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.0.RELEASE</version>
</parent>
<dependencies>
<!-- sprinboot web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
相关代码
@RestController
@Configuration
public class IndexController {
@Value("${mayikt.name}")
private String name;
@RequestMapping("/")
public String index(){
return "SpringBoot源码分析" + name;
}
}
public class MySpringApplicationRunListener implements SpringApplicationRunListener {
@Override
public void starting() {
System.out.println(">>>starting");
}
@Override
public void environmentPrepared(ConfigurableEnvironment environment) {
// 配置文件读取到程序中 思路需要自己将本地文件读取到容器中,再放入到springboot容器
Properties properties = new Properties();
try {
// 1. 读取我们的my.properties文件
properties.load(this.getClass().getClassLoader().
getResourceAsStream("my.properties"));
// 2. 读取名称名称为my
PropertySource propertySource = new
PropertiesPropertySource("my", properties);
//3. 将资源添加到springboot项目中
MutablePropertySources propertySources = environment.getPropertySources();
//4.通过该api接口可以将配置文件读取到springboot项目中
propertySources.addLast(propertySource);
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void contextPrepared(ConfigurableApplicationContext context) {
}
@Override
public void contextLoaded(ConfigurableApplicationContext context) {
}
@Override
public void started(ConfigurableApplicationContext context) {
}
@Override
public void running(ConfigurableApplicationContext context) {
}
@Override
public void failed(ConfigurableApplicationContext context, Throwable exception) {
}
}
@SpringBootApplication
public class AppMayikt {
public static void main(String[] args) {
SpringApplication springApplication = new SpringApplication(AppMayikt.class);
springApplication.run(args);
}
}
resources目录下文件
META-INF/spring.factories
org.springframework.boot.SpringApplicationRunListener=\
com.mayikt.MySpringApplicationRunListener
my.properties
mayikt.name= mayikt.com
运行结果:
3 SpringBoot自定义外部扩展文件02
报错原因,反射时没有构造函数,参考原代码增加构造函数。
public class MySpringApplicationRunListener implements SpringApplicationRunListener {
private SpringApplication application;
private String[] args;
public MySpringApplicationRunListener(SpringApplication application, String[] args) {
this.application = application;
this.args = args;
}
……
}
测试结果:
4 SpringBoot启动流程总结02
- getRunListeners(args); 读取META-INF/spring.factories 文件中SpringApplicationRunListeners 类型存入到集合中;
- listeners.starting(); 循环调用监听器starting方法;
- ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
listeners.environmentPrepared(environment);
读取配置文件到SpringBoot容器中;
读取配置有多种来源:classpath:/,classpath:/config/,file:./,file:./config/
classpath 与file读取有哪些区别?
Classpath 读取编译后的配置文件内容;File读取编译前的配置文件。
默认读取配置文件名称为:application
SpringBoot支持 yml、yaml、xml、properties类型配置文件读取。
3 SpringBoot启动流程总结03
- Banner printedBanner = printBanner(environment); 打印SpringBoot Banner;
- 创建SpringBoot上下文AnnotationConfigServletWebServerApplicationContext对象(java反射机制初始化);
- refreshContext(context); 刷新上下文,会走到spring里面refresh方法;
- 开始创建tomcat容器;
- 开始加载SpringMVC;
- afterRefresh 定义一个空的模版给其他子类实现重写;
- listeners.started(context); 使用广播和回调机制通知监听器SpringBoot容器已经启动成功;
- listeners.running(context); 使用广播和回调机制通知监听器可以正常运行SpringBoot项目;
- 最后返回当前上下文context。
(原内容由每特教育&蚂蚁课堂余老师编写,稍作修改)
SpringApplication类run方法源码:
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
configureHeadlessProperty();
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, listeners, exceptionReporters, ex);
throw new IllegalStateException(ex);
}
listeners.running(context);
return context;
}
6 SpringBoot源码分析课程总结
Spring体系核心设计模式分析:
Spring中有那些启动方式? 注解和xml
Spring中常用注解有那些:@ComponentScan、@Component、@Configuration、@Baan、@import
SpringBean的生命周期最核心组件:后置处理器
Spring事务底层原理,为什么会失效的呢?Aop技术,不能try
SpringAop中五个通知如何形成调用关联:=责任链模式和递归方法
Spring循环依赖是如何解决的呢?解决循环依赖底层原理什么?三级缓存
SpringMVC 如何去除web.xml运行的? 实现ServletContainerInitializer接口
SpringMVC适配器模式用于在什么地方?Handler多种类型处理
SpringBoot原理是什么?快速整合第三方框架、注解、内嵌tomcat
Springboot启动流程? 创建 SpringApplication对象,run启动
如何手写SpringBoot?三大核心理念+自定义starter+内嵌tomcat+使用Spring注解包装一遍