SpringBoot2-自动配置

本文介绍了SpringBoot的自动配置思想,包括原理和相关注解的解析,如@SpringBootConfiguration。同时,详细阐述了SpringBoot的启动流程,从初始化配置到创建ApplicationContext,再到run方法的执行步骤。
摘要由CSDN通过智能技术生成

SpringBoot - 自动配置(简洁版)

本文参考黑马程序员SpringBoot视频

一、自动配置思想

1.1、自动配置原理

  • 收集Spring开发者的编程习惯,整理开发过程使用的常用技术列表——》技术集A

  • 收集常用技术(技术集A)的使用参数,整理开发过程中每个技术的常用设置列表——》设置集B

  • 初始化SpringBoot基础环境,加载用户自定义的bean和导入的其他坐标,形成初始化环境

  • 技术集A包含的所有技术都定义出来,在Spring/SpringBoot启动时默认全部加载

  • 技术集A中具有使用条件的技术约定出来,设置成按条件加载,由开发者决定是否使用该技术(与初始环境做对比)

  • 设置集B作为默认配置加载(约定大于配置),减少开发者配置工作

  • 开放设置集B的配置覆盖接口,由开发者根据自身需要决定是否覆盖默认配置

1.2、@SpringBootConfiguration

  • @SpringBootConfiguration

    • @Configuration
      • @Component
        • @Indexed
  • @SpringBootConfiguration

    • @AutoConfigurationPackage
      • @Import({Registrar.class})
    • @Import({AutoConfigurationImportSelector.class})
  • @ComponentScan( excludeFilters = {@Filter(type = FilterType.CUSTOM, classes = {TypeExcludeFilter.class}), @Filter(type = FilterType.CUSTOM,classes = {AutoConfigurationExcludeFilter.class})})

    • @Repeatable(ComponentScans.class)

@SpringBootConfiguration注解是由上面哪些注解组合而成,而上面哪些注解,最主要的有两个:@Import({Registrar.class})@Import({AutoConfigurationImportSelector.class})

  • @Import({Registrar.class}):设置当前配置所在包作为扫描包,后续要针对当前的包进行扫描

  • @Import({AutoConfigurationImportSelector.class}):加载出配置集A

二、SpringBoot启动流程

1.1、启动流程思想

  • 初始化各种属性,加载成对象
    • 读取环境属性 - Environment
    • 系统配置 - spring.factories
    • 参数 - Arguments、application.properties
  • 创建Spring容器对象ApplicationContext,加载各种配置
  • 在容器创建前,通过监听器机制,应对不同阶段加载数据、更新数据的需求
  • 容器初始化过程中追加各种功能,例如统计时间、输出日志等

1.2、工作流程

SpringBoot项目的启动类中都是由SpringApplication.run(MuciApplication.class, args)启动的,那么就由这个类开始分析。

    public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
        return (new SpringApplication(primarySources)).run(args);
    }

由上面源码可知,最终分成两部分:一是SpringApplication对象的初始化,二是SpringApplication对象调用run方法。

1.2.1、SpringApplication的构造

该方式主要作用是加载各种配置信息、初始化各种配置对象

    public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
        this.sources = new LinkedHashSet();
        this.bannerMode = Mode.CONSOLE;
        this.logStartupInfo = true;
        this.addCommandLineProperties = true;
        this.addConversionService = true;
        this.headless = true;
        this.registerShutdownHook = true;
        this.additionalProfiles = Collections.emptySet();
        this.isCustomEnvironment = false;
        this.lazyInitialization = false;
        this.applicationContextFactory = ApplicationContextFactory.DEFAULT;
        this.applicationStartup = ApplicationStartup.DEFAULT;
        //传入类加载器,这种设计就是扩大该属性的使用范围,简单来说,这样设置之后,其他方法使用就不需要通过参数传递了。
        this.resourceLoader = resourceLoader;
        //就是简单判断传递的主类不是空
        Assert.notNull(primarySources, "PrimarySources must not be null");
        //将primarySources转成一个集合(去重)
        this.primarySources = new LinkedHashSet(Arrays.asList(primarySources));
        //推断当前容器加载的类型,根据是否存在某个类进行判断
        this.webApplicationType = WebApplicationType.deduceFromClasspath();
        //获取系统配置引导信息
        this.bootstrapRegistryInitializers = this.getBootstrapRegistryInitializersFromSpringFactories();
        //获取ApplicationContextInitializer.class对应的实例
        this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
        //初始化监听器,对初始化过程及运行过程进行干预
        this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
        //初始化引导类类名信息
        this.mainApplicationClass = this.deduceMainApplicationClass();
    }
1.2.2、SpringApplication的 run 方法

初始化容器,获取 ConfigurableApplicationContext 对象

    public ConfigurableApplicationContext run(String... args) {
        //相当于一个计时器
        StopWatch stopWatch = new StopWatch();
        //计时开始
        stopWatch.start();
        //系统引导信息对应的上下文对象
        DefaultBootstrapContext bootstrapContext = this.createBootstrapContext();
        ConfigurableApplicationContext context = null;
        //模拟输入输出信号,避免因缺少外设导致的信号传输失败,进而引发错误(模拟显示器,键盘,鼠标...)
        //java.awt.headless=true
        this.configureHeadlessProperty();
        //获取当前注册的可运行的监听器
        SpringApplicationRunListeners listeners = this.getRunListeners(args);
        //监听器执行了对应的操作步骤
        listeners.starting(bootstrapContext, this.mainApplicationClass);

        try {
            // 获取参数
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
            //将前期读取的数据加载成了一个环境对象,用来描述信息
            ConfigurableEnvironment environment = this.prepareEnvironment(listeners, bootstrapContext, applicationArguments);
            //做了一个配置 `spring.beaninfo.ignore` 备用
            this.configureIgnoreBeanInfo(environment);
            //控制打印banner
            Banner printedBanner = this.printBanner(environment);
            //创建容器对象,根据前期的应用类型判定
            context = this.createApplicationContext();
            //设置启动模式
            context.setApplicationStartup(this.applicationStartup);
            //对容器进行设置,参数来自于前期的
            this.prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
            //刷新容器环境
            this.refreshContext(context);
            //刷新完毕后做的后处理
            this.afterRefresh(context, applicationArguments);
            //计时结束
            stopWatch.stop();
            //判定是否记录启动时间的日志
            if (this.logStartupInfo) {
                //创建日志对应的对象,输出日志信息,包含启动时间
                (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
            }

            listeners.started(context);
            this.callRunners(context, applicationArguments);
        } catch (Throwable var10) {
            this.handleRunFailure(context, var10, listeners);
            throw new IllegalStateException(var10);
        }

        try {
            listeners.running(context);
            return context;
        } catch (Throwable var9) {
            this.handleRunFailure(context, var9, (SpringApplicationRunListeners)null);
            throw new IllegalStateException(var9);
        }
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值