8、SpringBoot自动装配原理篇

1、自动装配的设计思想

其实我们前面Bean的内容,其实就涉及到了自动装配的各个部分

image-20220412101133971

1.1、前期的调研工作

  • 对于开发人员来说,每天都会使用到很多的技术,而对于spring的开发人员来说,他们想知道大部分人使用的究竟是一些什么样的技术,对市场做了调研,将使用到的技术做一个整合,那么就得到了最终的一个技术集,所有的技术都在其中,逐步更新,包含了企业级开发中的所有常用技术
  • 进行进一步的调研,每个人使用这些技术还是有些区别的,这个时候,spring将这些技术当中的一些常用的参数做一个设置,得到一个设置集。该设置集针对的是技术集当中的每一个技术,例如:Redis数据库,最常用的是什么?端口号嘛--localhost:6379,全部列下来,这就是前期的调研工作。
  • 把这些事情做好之后,spring为我们做了一件事,自动装配。

1.2、自动装配

  • 你程序搭建的时候,现将springboot的基础环境搭建spring-boot-starter)出来,加载用户自定义的Bean和导入的其他坐标,形成初始化的环境,这个环境就是我开发的时候所要用的这些东西
  • 将技术集中的全部技术都定义出来,在Spring/SpringBoot启动的时候,默认全部加载
  • 将技术集中具有使用条件的技术,通过约定的方式定义出来,设置为按条件加载,由开发者决定是否使用该技术(与初始化环境的对比)
  • 那么问题来了,每一个技术的使用还需要大量的配置,相当麻烦,还记得上方的设置集嘛?
    • 如果某一个技术,大量的人都是用了某一种配置,那么我设置集就作为你这个技术的默认配置,进行加载---约定大于配置
  • 那么也肯定存在一种情况,你的默认配置和我搭不上,如何解决?
    • springboot开放了设置集的配置覆盖接口,由开发者决定是否去覆盖,如果与我开发发生冲突,那我肯定会选择去覆盖掉他

我想要买辆车,那么开发商需不需要将车上的这些组件全部给我定义好?例如:发动机,变速箱,车载导航,弹压监测....,你要不要无所谓,但是这些东西我的全部定义好,万一其他人需要使用呢?

技术集可以根据我们的使用需求,进行调整,你可以不要这些东西,但是有些东西你肯定得要,比如,你开车不能没有发动机吧?

先给你定义好,你需要使用的全部技术,然后根据你的使用需求,你来决定是要,还是不要,把这些东西确定好以后,你还可以进行一些个性化的配置----设置集

同样都是配置,根据设置的不同,那么产生的结果就不一样;例如:这个坐椅我不要真皮的坐椅,我就要牛皮的,可以吗?当然可以

设置集的作用就是基于你技术集的配置之上,给我做配置,我只需要设置,那么他马上就可以根据我的配置要求去使用

2、原理1:整体拆分

image-20220412220025985

就用之前讲过的猫和老鼠案例来讲解,其实也不用,只需要一个能跑起来的springboot项目即可

2.1、@SpringBootApplication

我们的程序是从这个启动类Application开始的,那么这个启动类,没有@SpringBootApplication注解肯定是不能运行的嘛,那这个注解就是我们的万物起源

image-20220412103924353

含义

这个注解是一个组合注解,他是一个接口,这个接口上方包含了多个注解

image-20220412104139053

最上方的四个注解不看,主要看下面三个,也就是说@SpringBootApplication实际上是这三个玩意儿的合体,这仨看明白了,自然就明白了

image-20220412104252391

2.2、注解1:@SpringBootConfiguration

这个怎么用不知道,但看名字就晓得这是SpringBoot的配置注解,是给SpringBoo配置的哦,点进去看看

image-20220412104937568

整体架构

@SpringBootConfiguration
	@Configuration
		@Component
	@Index

2.3、注解2:@EnableAutoConfiguration

是否启用自动配置,这个注解在@SpringBootApplication中,那么默认就代表启动了自动装配,点进去看看

image-20220412105550080

@AutoConfiurationPackage

使用了@AutoConfiurationPackage注解,这是什么,自动配置包?点进去

image-20220412105711400

到头了,最终他引入了一个组件

@Import(AutoConfigurationImportSelector.class)

ImportSelector,这是我们之前加载Bean方式的一种,通过返回一个String的数组来注册我们的Bean组件

结构

@EnableAutoConfiguration
    @AutoConfigurationPackage
        @Import(AutoConfigurationPackages.Registrar.class)
    @Import(AutoConfigurationImportSelector.class)

2.4、注解3:@ComponentScan

包扫描嘛,我们把那个注解展开看看

@ComponentScan(excludeFilters = {
        @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
        @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })

进入这个注解看看

image-20220412110117036

ComponentScans,扫描多个,应该就是集束整体扫描

excludeFilters

Filter:过滤器,这里指定了两个过滤规则

image-20220412110243873

TypeExcludeFilter.class

按类型排除性的过滤器

AutoConfigurationExcludeFilter.class

满足什么要求以后,他会做一定的排除,就是不扫描了,那不就是扫描不扫描,哪些东西要,哪些东西不要么

结论

实际上就是当这个注解加载完毕后,我哪些类可以不要了

2.5、整体目录结构

@SpringBootApplication
	// 项目配置
	@SpringBootConfiguration
		@Component
		// 这个注解是加载springboot的启动速度的,根据启动的过程创建全新的文件,加载Bean的时候加载这个文件
		@Index
	// 自动装配
    @EnableAutoConfiguration
    	@AutoConfigurationPackage
        	@Import(AutoConfigurationPackages.Registrar.class)
    	@Import(AutoConfigurationImportSelector.class)  
    // 项目过滤器,就是加载Bean的方式,只不过加载的花哨一点,高级一点
    @ComponentScan(excludeFilters = {
        @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
        @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })

那么我说句实话,很多东西都明白,那么是不是只需要搞清楚在@EnableAutoConfiguration中的@AutoConfigurationPackage的@Import(AutoConfigurationPackages.Registrar.class)

和与@AutoConfigurationPackage同级的@Import(AutoConfigurationImportSelector.class) 搞明白就可以了?

2.6、AutoConfigurationPackages.Registrar

Registrar是AutoConfigurationPackages的一个抽象类,内部有俩方法,我们看第一个

static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {

   @Override
   public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
      register(registry, new PackageImports(metadata).getPackageNames().toArray(new String[0]));
   }

   @Override
   public Set<Object> determineImports(AnnotationMetadata metadata) {
      return Collections.singleton(new PackageImports(metadata));
   }

}

1、registerBeanDefinitions

继承自ImportBeanDefinitionRegistrar和 DeterminableImports,第一个参数熟悉嘛?这是不是我们之前说过的加载Bean的一种方式,通过BeanDefinition这个对象来创建Bean?

1.1、ImportBeanDefinitionRegistrar的回顾

default void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry, BeanNameGenerator importBeanNameGenerator) {
    this.registerBeanDefinitions(importingClassMetadata, registry);
}

default void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
}

内部有俩个默认实现的方法,我们如果要使用它,那就必须要去覆盖掉这俩方法,使用谁覆盖掉谁,参数不多讲嘛,第一个是数据源,也就是你这个类,是被谁加载的(import),第二个参数是我们创建Bean的对象,第三个是创建Bean的名称

这里原码所使用的是覆盖掉第二种方法,也就是只要前面俩个参数

image-20220412141123623

1.2、覆盖的registerBeanDefinitions方法实现(注册BeanDefinition对象)

那么这个静态类Registrar覆盖了这个方法之后,他干了个什么事情呢?

  • 调用了一个register的方法,register--注册;
  • 两个参数
    • registry
      • 这个对象会通过所给予的Bean注册器--BeanDefinition,到容器当中去创建Bean
    • new PackageImports(数据源对象).getPackageNames().toArray(new String[0])
      • 这个我们单独提一个小点来讲

1.3、断点调试(new PackageImports(数据源对象))

对registerBeanDefinitions方法体打断点,对第二个参数进行一个计算

image-20220412142636935

  • new PackageImports()的计算

    • image-20220412142835781

    • image-20220412142901488

    • 这里看不出来是什么结果

  • new PackageImports(metadata).getPackageNames()的计算

    • image-20220412143002353

哦?这里就将我的包结构给读取出来了,或者说?我这个启动类,引导类--Application的所在路径被加载出来了

1.4、结论

这也是为什么平时老师经常会讲,自己新建的package,一定要包含在启动类的类路径,及其子包下,因为配置注解的时候,注解要生效,就会进行组件扫描,而组件扫描--@ComponentScan,他需要一个String类型的数组(其中一种),数组当中写的就是我们,需要被扫描的路径

2、内部调用的--register方法

重复一遍,这个方法需要两个参数,第一个参数是我们Bean的构造器,第二个参数是传递了一个我们启动类所在的包路径

image-20220412144306913

2.1、if-----registry.containsBeanDefinition(BEAN)

  • 这个程序启动之后,第一步会判定,我们这个注册器,是否包含一个,Bean定义叫做参数(Bean)

  • 这个参数叫什么呢?

    • image-20220412145825118
  • 就是这个类--AutoConfigurationPackages所对应的字节码文件的全路径类名嘛

他需要看我们加载过这个东西没有,加载过,走if,没有加载过,走下方的路

2.2、else----

我们显然是没有加载过的,那么他会执行一个什么样的方法?

image-20220412150107598

前期提要,这玩意儿是不是就是我们之前写过的

image-20220412150446850

它定义了一个Bean,这个Bean,这个Bean的名称就是我们那个变量名,也就是Autoxxxx这个类的全路径名,第二个参数new 了一个BasePackagesBeanDefinition,并且将我们刚刚的参数传递了过来,什么参数?(com.waves)

1、BasePackagesBeanDefinition

我不晓得这个类是干什么几把用的,但我晓得他这一坨,就是一个Bean的构造器--BeanDefinition,点进去看看

image-20220412151242897

简单说下这里干了个什么事情,你要扫描哪些包?我需要知道吧,我要不知道,我怎么给你扫描,所以程序用这种形式给我记录了一下,什么形式?--addBasePackages。

为什么是add,这里可以设置扫描不同的包,因此,这里可以选择添加进去,而不是通过设置的方式设置进去,因为还有许多的包都可以参与扫描的

3、总结

他这里就做了一件事情,设置当前启动类所在的包,作为扫描包,后续要针对我设置的这个包,进行一个扫描。

springboot启动之后,他需要知道加载你哪些包,中的,哪些Bean,这里就确定了这么一个东西

2.7、@Import(AutoConfigurationImportSelector.class)

no BB,直接点进去看

1、他所实现的接口

image-20220412161045803

很多接口,大致分为3类

  • 以Aware结尾的接口
  • Ordered接口
  • DeferredImportSelector接口

1.1、Aware

用发现;发觉解释比较好

image-20220412161329799

我这里做一个测试案例

  • 创建一个类去继承一个Aware结尾的接口

  • 将其定义为组件

    • image-20220412161807085
  • 实现ApplicationContextAware接口

    • image-20220412161921597
  • 实现其定义的一个方法

    • @Override
      public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
      
      }
      

无论实现的是XXXAware接口,这些接口都会让你实现一个方法,setxxxxAware()方法,并且需要一个对应的参数,这个参数是XXXXX,他既然需要,那我就给他一个这个对象嘛,但是后面抛的异常就不一定了

  • 定义方法体所需要的形参

    • // 所需要的形参
      private ApplicationContext applicationContext;
      
      @Override
      public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
          this.applicationContext = applicationContext;
      }
      
  • 方法设置完毕

我这里就做了一个set注入的操作,对吧,他有一个什么作用?

当我的任何一个spring环境当中的Bean实现了某个XXXX开头的Aware结尾的接口之后,我就可以在当前这个Bean所在的类里面,去使用这个XXXX对象

  • 设置一个方法,这个方法既然可以拿到ApplicationContext上下文对象,那我就可以使用他的方法对吧

    • 我这里就简单的打印一个IOC容器当中所有组件的名字

    • public void getBeanNames(){
          String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
          for (String bean : beanDefinitionNames) {
              System.out.println(bean);
          }
      }
      
  • 启动主程序,开始调用

    • image-20220412163335220

image-20220412163403453

没毛病吧,用Aware接口是可以注入到我需要使用的那些资源的

现在明白了吧,如果你想使用环境(EnvironmentAware);Bean工厂(BeanFactoryAware);资源加载器(ResourceLoaderAware);Bean的类加载器(BeanClassLoaderAware);他们的对象该怎么办?

就去实现对应的接口就可以了,前提是你实现他们这些接口的类必须被Spring加载到了哈,不然我也不会写@Component的,你这个类得是一个需要被Spring所管理的对象,Bean,才可以

1.2、Ordered

Order;意为排序,点进去看看内部是什么样的

public interface Ordered {
    int HIGHEST_PRECEDENCE = -2147483648;
    int LOWEST_PRECEDENCE = 2147483647;

    int getOrder();
}

内部一个最大值,一个最小值,其中有一个getOrder()的方法,获取排序?也就是加载顺序

image-20220412164202704

你当前这个类,加载的时候,在Spring容器当中的加载顺序,为什么需要这个顺序?

1、为什么需要这个顺序?

我这里有50个bean,我现在要加入第51个Bean,而51个Bean的,加载的前提是,第37个Bean必须是存在的,不然我不会加载;那么现在出现一个情况,我51和37的位置互换了,那么51号Bean还能被加载吗?不能,因为37还没有加载,那么我的功能就不完全了,所以这个顺序很重要

我这里将---AutoConfigurationImportSelector,的类展开,我看他内部的方法中是否存在这个getOrder()

image-20220412164657418

显然是存在的嘛,并且有个值,是多少我就不晓得了,反正这里它有个加载顺序

1.3、DeferredImportSelector

Deferred:推迟,延迟

前面这一坨不认识,后面的ImportSelector非常熟悉,这是一种加载Bean的方式,我们点进这个接口看看

image-20220412165958532

很显然,这个接口继承了ImportSelector接口,说明他的功能会比继承的接口更加的广泛,也就是说,这是一个推迟的选择器

而我们的这个AutoConfigurationImportSelector这个类实现了这个接口,那么可以得出一个结论,这个类或者说是这个Bean,一定会比其他Bean加载的时间要晚

1、interface Group

Group--意为组,也就是说,推迟的类并非他一个,而是有许多的类,整合为一个组,一起推迟加载

image-20220412202106775

我们主要观看Group中定义的方法

  • process

    • 需要的参数为
    • image-20220412202151740
  • 那我们看下,这个接口是一个子接口,那么实现他父接口的实现类AutoConfigurationImportSelector,对其实现了什么内容

2、AutoConfigurationImportSelector--实现的process方法、

看不懂对吧,没关系

image-20220412202644824

  • Assert---断言:

    • 那么这一坨实际上是对某种情况进行一个判定
    • image-20220412202835685
  • 那么下方就是不符合这个情况所走的条件

    • image-20220412202944197

    • 这里的get方法就是我们要解读的方法

      • image-20220412203207027
3、getAutoConfigurationEntry

image-20220412203225505

3.1、if--首先判断你给定我的这个注解(annotationMetadata)源注解是否是一个不可用的?那不屁话吗,他的源注解是谁?是谁调用的它?启动类嘛~启动类的那个注解调用的?SpringBoot下的EnableAutoConfiguration下的AutoConfigurationImportSelector类实现的process方法

image-20220412203503452

是否是一个不可用的?那显然不是啊,如果是的话就会返回一个空对象

3.2、获取源注解当中的属性--getAttributes(annotationMetadata);

什么属性?

image-20220412203856804

源注解的俩属性

image-20220412203942940

这俩注解干啥用的?

3.3、排除部分不需要的技术-----干啥用的这俩b玩意儿?

在我们的EnableAutoConfiguration这个注解点进去以后

image-20220412204105182

下方俩属性,这俩属性就是读取的属性

如果我们在做装配的时候,SpringBoot不是给我提供了一个技术集吗,里面包含了大量企业级开发的常用技术,我如果我不想用哪些技术,我可以在这里面配置

  • exclude--按照Class,类的形式匹配
  • excludeName--按照字符串的名称匹配
3.4、所以这一步

image-20220412204356874

他去把这俩东西exclude和excludeName拿出来,如果你不想要的东西,我先获取,然后把它拿掉

3.5、最核心的配置--getCandidateConfigurations

image-20220412204642870

获得候选配置

image-20220412204521234

返回值是一个List集合,内部包含的是String类型的字符串,传递了一个源注解,和得到的不需要被封装的技术的名称对象

3.6、什么是候选配置?

SpringBoot封装的技术集A中,有着大量的配置,那些技术是都需要加载的吗?不一定啊,但是在哪里摆着的一些是有可能需要被加载的,这个有可能的范围,需要实际情况去斟酌,不加载的和可能会加载的;是两码事,搞清楚

点进这个候选配置的方法中getCandidateConfigurations()--

image-20220412205055397

  • 主要分为三步
    • 通过loadFactoryName的操作,获取到了我们可能会被加载的技术
    • 然后通过一个断言匹配
    • 最终返回一个configurations的对象
3.7、getCandidateConfigurations----loadFactoryNames

image-20220412205315299

  • ClassLoade--类加载器,这个不是我们需要看的
  • 最终的返回值,调用的方法,是我们需要注意的
    • image-20220412210324986
3.8、loadSpringFactories

逐个解析,因为代码量很大

image-20220412210439877

从缓存当中获取我们,类加载器的各种信息,判断是否为空,如果不为空就返回,为空往下面看

image-20220412210543953

这个getResources使我们需要看的

3.9、getResources

image-20220412210630441

通过类加载器,的读取外部资源的方法(getResources)读取一个外部文件,这个外部文件点进去看看

image-20220412210713228

"META-INF/spring.factories"

META-INF下的spring.factories文件,这个文件下配置了大量的spring工厂,这个文件在哪儿呢?

3.10spring.factories文件的位置和装载的内容

我这里导入的spring-boot的核心配置文件的版本是image-20220412210935563

在它的配置文件下是什么都找不到的,我们需要找autoconfiguration,自动配置下的META-INF,因为这玩意儿本身就是在@EnableAutoConfiguration的注解下

image-20220412211136535

image-20220412211214973

image-20220412211330508

人家这里给你写明了,Auto Configure--自动装配,那说明我们之前的SpringBoot封装的技术集,就是这一大坨东西,从红框开始的这一大坨内容,就是自动装载的全部技术

这里urls就获取到的配置文件中全部技术的装载,然后使用一个while循环进行加载,最终将这个内容,装载到另外一个区域里,就是我们最里面套的那个东西

image-20220412212229815

3.11、回到getAutoConfigurationEntry的方法中

getCandidateConfigurations这个方法最终给我们返回了一个加载着springboot的技术集中的内容,的list集合,这里面加载的项,就是我们刚刚看到的那一大坨配置项

image-20220412215045543

这里面加载的项就是我们刚刚那些AutoConfiguration的项

image-20220412215638590

3.12、总结

这个地方(getResources)他做了一件事情,就是把spring.factories的配置加载到了内存中,回头这些东西就会成为我们的技术集

2.8、自动装配的案例

我这里选择使用redis.RedisAutoConfiguration--redis的这项技术

image-20220412220942162

我们来看看这个类

1、RedisAutoConfiguration

image-20220412221000693

看看这些注解,熟悉嘛?

1.1Configuration---这个类是一个配置类,并且没有启用代理对象

1.2、ConditionalOnClass--如果这个类,存在,RedisAutoConfiguration才会被加载到容器当中

  • 那么我们看看这个类是否存在吧?点进去看看

  • image-20220412221320243

  • 就是找不到这个类,那么这个类在哪里呢?

  • spring-boot-starter-data-redis

    • image-20220412221545953
  • 那这个类就被加载到了嘛,所以我们这个RedisAutoConfiguration会被加载到容器当中嘛

    • image-20220412221633163
    • image-20220412221943022
  • 我现在将这个依赖取消掉

    • image-20220412221736592
  • 我去重新打印一遍容器中加载的组件

    • image-20220412221809934
  • 释放注解,打印加载的组件

    • 看是不是都加载上了
    • image-20220412221852478

1.3、@EnableConfigurationProperties(RedisProperties.class)

image-20220412222038153

这是什么,强行让一个类加载成Bean,关联注解,我们点金这个RedisProperties看看

image-20220412222137996

读取了一个配置文件,那是不是跟我们读取yml配置文件当中的内容一样?还记得毛和老鼠吗

image-20220412222257797

这个类中我读取了yml的配置文件

image-20220412222306188

image-20220412222330573

1.4、RedisTemplate

image-20220412222800669

下方的stringRedisTemplate也是一样的道理

2、总结

image-20220412222924677

我们通过读取这个配置文件的信息,将技术集当中的配置加载到了我们的环境当中,但是这些配置真的被加载到了Bean上吗?那显然是没有的,上方的案例就是例子

加载完毕之后,会进行一个条件检测,检测通过,那么就将配置加载到容器当中

image-20220412223141423

将技术集中具有使用条件的技术约定出来,形成按条件加载,使用与否,就是对比我们开发者定义的初始化环境,也就是我们的pom.xml中导入的坐标,Grandle也是,只要能导包的都行

image-20220412223242149

那么比对完毕之后,他才会去进行一个配置,配置在哪儿?就是别人定义好的配置类,这个配置类读取配置文件的信息完成值的注入

image-20220412223352461

这个技术当中的参数,可能有默认值的,也可能没有默认值的,有没有,取决于用什么样的技术,别人给你实现的配置方法

image-20220412223508686

当然,这是默认配置,如果这个配置,我们可以根据默认配置去加载它。

如果我们不想使用默认配置,那么就会根据开发者的自身需求去覆盖默认的配置,例如我在yml配置文件中通过配置port的属性去修改他的端口号,当然,这里应该写别的值容易区分

image-20220412223648533

3、整体总结

image-20220412223825552

我前面大概全部复述了整体的一个流程,建立在我听得懂的基础之上,

spring默认启动的时候,加载了无数技术的自动配置类,用来检测你当前的环境需不需要加载对应的技术---pom.xml

根据自动配置类的加载去确认这个类是否要激活,条件只要能成立,那么他就能激活

image-20220412224027223

3.1、问题所在

你现在的自动配置类能不能少加载点东西呢,我用不到那么多的配置类,能不能提高点速度,别做那么多了,这个也是可以的

4、干预自动配置

4.1、添加自动配置

我们导入一个MP的坐标

<!-- MP -->
<dependency>
  <groupId>com.baomidou</groupId>
  <artifactId>mybatis-plus-boot-starter</artifactId>
  <version>3.5.1</version>
</dependency>

打开我们所加载的信息

image-20220412234210080

MP也有自己的spring.factories配置文件,我们点开看看

image-20220412234237283

Auto Configure,不用我多说了把,自动配置,我们掐掉上面的,上面的不是所需要的,上面的配置是环境的配置,我们掐掉第一个,留下自动配置加载的第一个配置,我这里是自己新建了一个spring.factories的配置文件哈,别人的是没办法改的

image-20220412234450789

3.3、开始自动配置

怎么配置,我之前在启动类当中是加载了我的这个类的,什么类?猫和老鼠的类

image-20220412234615500

我这个类除了没有限制条件,其他的东西基本和原码写的一模一样把

image-20220412234639549

引导类中我引入了这个类,让其成为了一个组件,我也因此可以调用这其中的方法

image-20220412234805706

我现在在配置文件当中将刚刚复制的那个MP的配置类的全路径名变为我自己的猫和老鼠的全路径名,那么这个时候我就完成自己的自动配置了,那么现在我要取消掉启动类当中的引入注解

image-20220412235156156

我通过配置文件的方式实现了自动配置,我的猫和老鼠的方法被加载出来了

image-20220412235232677

我没有通过注解去让他自动配置吧,并没有

4.2、排除自动配置

就是我加载的时候不想要这个默认加载的配置,让运行速度加快,或者有些时候技术冲突,那么我如何操作?

image-20220412235951671

这是我IOC容器当中加载的组件,我现在不香要他,我该如何干预?排除

1、配置文件的方式

image-20220413000949543

0匹配

image-20220413001026835

2、注解的方式

我们的@EnableAutoConfiguration中有俩属性是用于排除不需要的配置

image-20220413001311702

而@SpringBootApplication这个注解继承了这俩个属性

image-20220413001350953

我们这里就通过路径名排除吧

@SpringBootApplication(excludeName="org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration")

5、整体总结

image-20220413001746613

posted @ 2022-05-31 20:17  澜璨  阅读(476)  评论(0编辑  收藏  举报