• springboot 自动装配原理


    一.原理解释

    Spring Boot的自动配置是Spring框架的一个重要特性,它旨在简化应用程序的开发和部署过程。自动配置通过基于类路径中的依赖关系和配置文件内容来预先配置Spring应用程序的各种组件和功能。这样,我们可以在无需显式配置大量参数的情况下,快速搭建一个运行良好的Spring应用程序,极大的提高了我们的开发效率。

    下面我们对于Spring Boot自动配置的工作原理做一个详细解释(我们只谈原理和概念,不设计实现)
    springboot的自动装配使用了很多的技术点,它是在别的基础基础上做了整合,springboot在启动流程的时候,通过加载mata-info/spring.factory文件,加载自动化配置的文件。它使用的主要技术点主要有以下几点

    1.Spring Boot Starter :

    Spring Boot提供了一系列Starter模块,每个Starter模块都包含了特定功能的默认依赖和配置。例如,spring-boot-starter-web包含了构建Web应用程序所需的依赖和配置。这些Starter模块通过自动配置来简化应用程序的搭建,开发者只需添加相应的Starter依赖,即可自动启用相关功能。

    条件装配:

    Spring Boot的自动配置采用了条件装配的机制。条件装配根据特定条件来决定是否创建特定的Bean或应用特定的配置。这些条件可以基于类路径中存在的依赖、配置属性的值、环境变量或其他Spring Bean的存在等。这样,当满足特定条件时,相关的Bean会被自动创建和配置,否则它们将被跳过。条件装配主要依赖于条件注解

    条件注解:

    Spring Boot中有许多条件注解,这些注解用于根据特定条件来启用或禁用配置。例如,@ConditionalOnClass注解表示只有类路径中存在指定的类时,相关配置才会生效。@ConditionalOnProperty注解则允许根据配置属性的值来决定是否启用某个配置。

    Spring Boot的启动过程:

    当Spring Boot应用程序启动时,会触发自动配置的过程。首先,它会扫描类路径上的所有Starter模块,并加载它们的自动配置类。然后,Spring Boot会根据条件装配机制,检查是否满足自动配置的条件,并决定是否创建相应的Bean和应用相关的配置。

    springboot的自动配置

    自动配置类的优先级:

    在某些情况下,可能存在多个自动配置类都能满足条件的情况。为了解决这种冲突,Spring Boot为自动配置类定义了优先级。具有更高优先级的配置类将覆盖具有较低优先级的配置类。这样,开发者可以通过自定义配置类来覆盖Spring Boot默认的自动配置行为。

    自定义自动配置:

    Spring Boot允许开发者定义自己的自动配置类。要创建自定义的自动配置,只需在类上添加@Configuration注解,并在类中配置所需的Bean。然后,Spring Boot会在启动过程中将这些自定义配置类纳入自动配置的流程中。

    其实总言而之,自动配置就是做了封装,对于我们习惯性的操作全部进行简化!在实现上,Spring Boot的自动配置通过条件装配机制和Starter模块来简化Spring应用程序的开发过程。它根据类路径中的依赖、配置属性的值以及其他条件来决定是否创建特定的Bean和应用相关的配置。这种自动化的特性使得开发者可以更加专注于业务逻辑,而无需过多关注繁琐的Spring配置。

    约定大于配置

    "约定大于配置"是一种软件开发的设计原则,它强调通过制定一系列约定和默认规则,来降低配置的复杂性,从而简化开发和部署过程。这个原则在很多开发框架和工具中都有应用,其中就包括Spring Boot,既然讲到了自动配置,我们就做一个延伸,对于此概念也做一个解释!

    具体来说,"约定大于配置"的理解可以从以下几个方面:

    默认约定:

    在"约定大于配置"的理念下,开发框架或工具会预定义一些默认约定。这些默认约定规定了开发者在遵循特定命名规则、目录结构或配置属性时将会获得某种预期的行为或功能。通过使用这些默认约定,开发者无需显式配置大量细节,可以快速启动和运行应用程序。

    简化配置:

    通过遵循约定,很多配置信息可以被自动推断或者从默认值中获取。这样,开发者在进行配置时,只需关注少量的关键配置,而不用逐个配置每个细节,从而简化了配置过程。

    提高一致性:

    约定大于配置有助于在团队开发中建立一致的代码风格和项目结构。所有团队成员都遵循相同的约定,从而降低了沟通和协作的成本。

    降低学习曲线:

    使用约定大于配置的框架或工具,开发者无需过多了解复杂的配置选项,只需要学习一些基本的约定即可开始工作。这有助于降低学习曲线,使新手能够更快地上手。

    灵活性和扩展性:

    尽管约定大于配置提供了默认规则,但它并不意味着开发者完全不能进行自定义配置。框架通常会提供一些扩展点,允许开发者根据自己的需求进行配置和定制。

    总体而言,"约定大于配置"是一种设计原则,它通过提供默认约定和简化配置的方式,降低了应用程序开发和部署的复杂性,使开发者能够更加专注于业务逻辑的实现,从而提高开发效率和代码质量。

    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:实现自动装配的核心注解

    EnableAutoConfiguration 只是一个简单地注解,自动装配核心功能的实现实际是通过 AutoConfigurationImportSelector 类。

    在这里插入图片描述
    我们现在重点分析下 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 configurations = getCandidateConfigurations(annotationMetadata, attributes);
        //第4步:符合条件加载
        //去掉重复的配置类
       configurations = removeDuplicates(configurations);
        //执行
       Set exclusions = getExclusions(annotationMetadata, attributes);
        //校验
       checkExcludedClasses(configurations, exclusions);
        //删除
       configurations.removeAll(exclusions);
        //过滤
       configurations = getConfigurationClassFilter().filter(configurations);
       fireAutoConfigurationImportEvents(configurations, exclusions);
        //创建自动配置的对象
       return new AutoConfigurationEntry(configurations, exclusions);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    第 1 步:判断自动装配开关是否打开。默认 spring.boot.enableautoconfiguration = true,可在 application.properties 或 application.yml 中设置在这里插入图片描述
    在这里插入图片描述
    第 2 步:用于获取 EnableAutoConfiguration注解中的 exclude 和 excludeName。

    在这里插入图片描述
    第 3 步

    获取需要自动装配的所有配置类,读取META-INF/spring.factories

    先进入 getCandidateConfigurations() 方法中:

    在这里插入图片描述
    进入 loadFactoryNames() 方法中:

    在这里插入图片描述
    再进入 loadSpringFactories() 方法中:

    在这里插入图片描述
    在这里插入图片描述
    从下图可以看到这个文件的配置内容都被我们读取到了。

    在这里插入图片描述
    不光是这个依赖下的 META-INF/spring.factories 被读取到,所有 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类为本人书写,类中实际的属性要多的多

  • 相关阅读:
    English语法_形容词/副词3级-比较级_常用短语
    【PMP考前冲刺题-第一小节(2022.7)】
    自定义View实现波浪荡漾效果
    使用c:forEach出现页面空白,没有数据
    不用445端口,替代Windows共享,局域网文件共享新方式
    2023年9月30日
    Excel VLOOKUP实用教程之 06 vlookup如何从使用通配符进行部分查找?(教程含数据excel)
    pytorch深度学习实战lesson21
    k8s-服务网格实战-入门Istio
    TiDB v6.0.0 (DMR) :缓存表初试丨TiDB Book Rush
  • 原文地址:https://blog.csdn.net/tian830937/article/details/132892607