SpringBoot自动配置原理详解

​自动配置原理

1.什么是 SpringBoot 自动配置

        没有 Spring Boot 的情况下,我们引入第三方依赖之后,需要手动配置,比如需要手动将引入的第三方依赖通过 xml 配置或注解的方式注入到 Ioc 容器中,并可能需要对注入到Ioc容器中的bean进行一些配置,非常麻烦。但是,在Spring Boot 中,我们直接引入一个 starter 即可。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

        SpringBoot 定义了一套接口规范,这套规范规定:SpringBoot 在启动时会扫描外部引用 jar 包中的 META-INF/spring.factories 文件,将文件中配置的类型信息加载到 Spring 容器(此处涉及到 JVM 类加载机制与 Spring 的容器知识),并执行类中定义的各种操作。对于外部 jar 来说,只需要按照 SpringBoot 定义的标准,就能将自己的功能装置进 SpringBoot。

引入 starter 之后,我们通过少量注解和一些简单的配置就能使用第三方组件提供的功能了。

所以说,其实自动装配可以简单的理解为:通过注解或者一些简单的配置就能在spring boot的帮助下实现某款功能。

2.springboot是如何实现自动配置的

首先我们先来看一些 SpringBoot 项目的核心注解 @SpringBootApplication,这个注解位于启动类上方:

点击 @SpringBootConfiguration 注解,发现这个注解其实就是一个配置注解,SpringBoot 把 @Configuration 注解做一个包装。 

所以说 @SpringBootApplication 是一个复合注解,大概就可以把 @SpringBootApplication 看作是 @Configuration、@EnableAutoConfiguration、@ComponentScan 注解的集合。根据 SpringBoot 官网,这三个注解的作用分别是:

  • @EnableAutoConfiguration:启用 SpringBoot 的自动配置机制。

  • @Configuration:允许在上下文中注册额外的 bean 或导入其他配置类,作用与 applicationContext.xml 的功能相同。

  • @ComponentScan: 扫描包下的类中添加了@Component (@Service,@Controller,@Repostory,@RestController)注解的类 ,并添加的到spring的容器中,可以自定义不扫描某些 bean。如下图所示,容器中将排除TypeExcludeFilter和AutoConfigurationExcludeFilter。

也就是说,@EnableAutoConfiguration 是实现自动装配的核心注解,@EnableAutoConfiguratio的内部如下所示。

自动装配核心功能的实现是通过EnableAutoConfiguration内部的AutoConfigurationImportSelector类。

我们现在重点分析下 AutoConfigurationImportSelector 类到底做了什么?

AutoConfigurationImportSelector 类的继承体系如下:

可以看出,AutoConfigurationImportSelector 类实现了 ImportSelector 接口,也就实现了这个接口中的 selectImports 方法,该方法主要用于获取所有符合条件的类的全限定类名,需要为这些类创建对象并加载到 IoC 容器中

这里我们需要重点关注一下 getAutoConfigurationEntry方法,这个方法主要负责加载自动配置类的。该方法调用链如下:

现在我们结合 getAutoConfigurationEntry 方法的源码来详细分析一下:

protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
    //第1步:判断自动装配开关是否打开
   if (!isEnabled(annotationMetadata)) {
      return EMPTY_ENTRY;
   }
    //第2步:用于获取注解中的exclude和excludeName。
    //获取注解属性
   AnnotationAttributes attributes = getAttributes(annotationMetadata); 
    //第3步:获取需要自动装配的所有配置类,读取META-INF/spring.factories
    //读取所有预配置类
   List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
    //第4步:符合条件加载
    //去掉重复的配置类
   configurations = removeDuplicates(configurations);
    //执行
   Set<String> exclusions = getExclusions(annotationMetadata, attributes);
    //校验
   checkExcludedClasses(configurations, exclusions);
    //删除
   configurations.removeAll(exclusions);
    //过滤
   configurations = getConfigurationClassFilter().filter(configurations);
   fireAutoConfigurationImportEvents(configurations, exclusions);
    //创建自动配置的对象
   return new AutoConfigurationEntry(configurations, exclusions);
}

第 1 步:判断自动装配开关是否打开。默认 spring.boot.enableautoconfiguration = true,可在 application.properties 或 application.yml 中设置。

第 2 步:用于获取 EnableAutoConfiguration 注解中的 exclude 和 excludeName。

第 3 步:  META-INF/spring.factories 读取需要自动装配的所有配置类。

先进入 getCandidateConfigurations() 方法中:

进入 loadFactoryNames() 方法中:

再进入 loadSpringFactories() 方法中:

所有 Spring Boot Starter 下的 META-INF/spring.factories 都会被读取到。 

第 4 步:到这里可能面试官会问你:spring.factories 中这么多配置,每次启动都要全部加载么?

很明显,这是不现实的。我们 debug 到后面你会发现,configurations 的值变小了。

因为,这一步有经历了一遍筛选过滤,@ConditionOnXXX 中的所有条件都满足,该类才会生效。

Spring Boot 提供的条件注解如下:

  • @ConditionalOnBean:当容器里有指定 Bean 的条件下
  • @ConditionalOnMissingBean:当容器里没有指定 Bean 的情况下
  • @ConditionalOnSingleCandidate:当指定 Bean 在容器中只有一个,或者虽然有多个但是指定首选 Bean
  • @ConditionalOnClass:当类路径下有指定类的条件下
  • @ConditionalOnMissingClass:当类路径下没有指定类的条件下
  • @ConditionalOnProperty:指定的属性是否有指定的值
  • @ConditionalOnResource:类路径是否有指定的值
  • @ConditionalOnExpression:基于 SpEL 表达式作为判断条件
  • @ConditionalOnJava:基于 Java 版本作为判断条件
  • @ConditionalOnJndi:在 JNDI 存在的条件下差在指定的位置
  • @ConditionalOnNotWebApplication:当前项目不是 Web 项目的条件下
  • @ConditionalOnWebApplication:当前项目是 Web 项 目的条件下 

通过一个具体技术说明自动装配原理

第一步:先找到 SpringBoot 项目中的启动类,根据启动类上方的 @SpringBootApplication 注解一层层的找到下图中的类。在这个类中有一个常量,其常量值是spring.factories文件的所在位置,在这个文件中定义了第三方依赖中所有技术的全路径名

第二步:从spring.factories文件中随便找到一个技术,以redis为例,然后在当前springboot项目中双击Shift,在弹出的页面中搜索找到RedisAutoConfiguration类。如下图所示:

        由RedisAutoConfiguration类上面的注解可知,RedisAutoConfiguration类有一个bean加载控制的注解。也就是说,当前类要想加载成bean,必须在当前项目中导入RedisOperations这个类,也就是当前类加载成bean的触发条件,而RedisOperations这个类在我们导入的redis的依赖包中。

        在RedisAutoConfiguration类上方有一个 @EableConfigurationProperties 注解。进入@EableConfigurationProperties 注解里的RedisProperties类中,如下图所示, RedisProperties 类上方有一个 @ConfigurationProperties 注解,此注解用来将配置文件中前缀为 spring.redis 的配置值绑定到类中属性上。

        但是可以发现,RedisProperties类里很多属性已经配置了默认值。也就是说,如果 springboot 配置文件中没有配置值,则 springboot 会采用 RedisProperties 类中属性的默认值来作为redis这项技术的默认配置值。

注意:

spring.factories 功能在 SpringBoot 2.7 已经废弃,并且在 SpringBoot 3.0 移除。但机制还是类似的。

上图中的RedisProperties类为本人书写,类中实际的属性要多的多

  • 37
    点赞
  • 109
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
Spring Boot是一个简化Spring应用开发的框架,它通过自动配置的方式来减少开发者的工作量,提高开发效率。SpringBoot自动配置原理是什么呢? 首先,SpringBoot自动配置是基于SpringBoot的starter依赖功能实现的。starter依赖本质上是一个Maven项目,里面包含了一些依赖和必要的资源,只需将这个项目引入到应用中,就能自动加载依赖并进行一些默认配置Spring Boot框架中一些核心的starter依赖包括spring-boot-starter-web、spring-boot-starter-data-jpa、spring-boot-starter-data-redis等等,开发者可以根据自己的需要引入合适的starter依赖。 其次,SpringBoot自动配置是基于条件注解实现的。条件注解是Spring框架提供的一种特殊注解,它能够根据指定的条件来判断是否需要加载某个组件或配置Spring Boot中,提供了很多条件注解,如@ConditionalOnClass、@ConditionalOnProperty等等,它们可以根据类是否存在、属性是否配置等条件来决定是否加载某个组件或配置。 最后,SpringBoot自动配置还包含了一些默认的配置,这些默认配置可以通过自定义配置来覆盖或扩展。例如,在使用spring-boot-starter-web时,SpringBoot会默认配置Tomcat容器来运行Web应用,如果开发者需要使用其他容器如Jetty或Undertow,可以写一个配置类来覆盖默认配置。 综上所述,SpringBoot自动配置是基于starter依赖、条件注解和默认配置实现的。它大大减少了开发者的工作量,提高了开发效率,同时也保证了应用的可靠性和稳定性。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

真滴book理喻

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值