互联网架构-SpringBoot源码深度解析-034:SpringBoot配置解析源码分析

1 SpringBoot启动流程总结01

课题内容:

  1. SpringBoot源码分析之配置文件解析原理
  2. SpringBoot启动流程整体源码总结
  3. Spring源码总结之Spring体系面试题复习

总结SpringBoot启动流程
核心分为两个步骤;

  1. 创建 SpringApplication对象
  2. 调用SpringApplication run 实现启动,同时返回当前的容器上下文

分析流程:

  1. 创建SpringApplication对象 SpringBoot容器初始化操作;
  2. 获取当前应用启动类型 原理:判断当前classpath是否有加载servlet类,如果有,返回Servlet web启动方式;
    webApplicationType 分为三种类型:
    1.响应式启动 (Spring5新特性)
    2.None 不会嵌入web容器启动 (将SpringBoot项目放入外部服务器运行)
    3.SERVLET 基于Web容器启动
  3. setInitializers 读取SpringBoot包下面的META-INF/spring.factories获取到对应ApplicationContextInitializer 装配到集合中;
  4. setListeners读取SpringBoot包下面的META-INF/spring.factories获取到对应ApplicationListener装配到集合中;
  5. mainApplicationClass 获取当前运行的主函数;
  6. 调用SpringApplication run方法实现启动;
  7. 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

  1. getRunListeners(args); 读取META-INF/spring.factories 文件中SpringApplicationRunListeners 类型存入到集合中;
  2. listeners.starting(); 循环调用监听器starting方法;
  3. 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

  1. Banner printedBanner = printBanner(environment); 打印SpringBoot Banner;
  2. 创建SpringBoot上下文AnnotationConfigServletWebServerApplicationContext对象(java反射机制初始化);
  3. refreshContext(context); 刷新上下文,会走到spring里面refresh方法;
  4. 开始创建tomcat容器;
  5. 开始加载SpringMVC;
  6. afterRefresh 定义一个空的模版给其他子类实现重写;
  7. listeners.started(context); 使用广播和回调机制通知监听器SpringBoot容器已经启动成功;
  8. listeners.running(context); 使用广播和回调机制通知监听器可以正常运行SpringBoot项目;
  9. 最后返回当前上下文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注解包装一遍

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值