大聪明教你学Java | 深入浅出聊 SpringBoot 中的 starter 机制

2,102 阅读8分钟

前言

“我正在参加「掘金·启航计划」”

🍊作者简介: 不肯过江东丶,一个来自二线城市的程序员,致力于用“猥琐”办法解决繁琐问题,让复杂的问题变得通俗易懂。

🍊支持作者: 点赞👍、关注💖、留言💌~

我们都知道,Spring 的功能非常强大,但也存在一些弊端。例如我们需要手动去配置大量的参数,需要我们管理大量的 jar 包等等。后来,官方为了简化配置,同时可以让开发者们能更好的专注于业务的开发,Spring 官方引入了 SpringBoot 的概念。提到 SpringBoot 各位小伙伴肯定是不陌生了,我们几乎每天都在和它打交道,就是不知道各位小伙伴在使用 SpringBoot 的时候有没有注意过 pom.xml 中的 starter 依赖呢~ 今天大聪明就和大家深入浅出聊 SpringBoot 中的 starter 机制😊

SpringBoot 中的 starter 机制

什么是 starter

SpringBoot 在配置上相比 Spring 要简单许多, 其核心在于 spring-boot-starter,在使用 SpringBoot 来搭建一个项目时,只需要引入官方提供的 starter 后就可以直接使用,免去了各种繁琐的配置流程。简单来讲就是,starter 帮助开发者们引入了一些相关依赖和一些初始化的配置,从而可以让开发者们更专注于开发。Spring 官方提供了很多 starter,第三方也可以定义 starter。为了加以区分,starter从名称上进行了如下规范:

  • Spring 官方提供的 starter 名称为 spring-boot-starter-xxx,例如 spring-boot-starter-web
  • 第三方提供的 starter 名称为 xxx-xxx-boot-starter,例如由苞米豆提供的 mybatis-plus-boot-starter

说到这,各位小伙伴可能有疑问了,SpringBoot 为什么可以帮我们简化项目的搭建的工作呢?它是如何做到这点的呢?🤔

其实这就要归功于它提供的两大功能了,起步依赖和自动配置。

起步依赖

起步依赖,其实就是将具备某种功能的相关依赖打包到一起,这样可以简化依赖导入的过程(我们可以将其理解为依赖整合)。例如,我们在导入 spring-boot-starter-web 时,和 web 开发相关的依赖都一起导入到项目中了。我们点开 spring-boot-starter-web 依赖后就可以发现,它下面还包含着众多所需要的基础依赖 👇

在这里插入图片描述

自动配置

自动配置,顾名思义就是无须手动配置 xml 文件,当我们引入相关依赖后就可以自动配置并管理 bean,极大的简化了开发过程。SpringBoot 完成自动配置共分为五个关键的步骤:

  1. 基于配置文件的 Bean 配置
  2. 自动配置条件依赖
  3. Bean 参数获取
  4. Bean 的发现
  5. Bean 的加载

接下来我们以 mybatis-plus-boot-starter 为例子,具体说一下这五个流程👇

🍊 ① 基于配置文件的 Bean 配置 🍊 当我们引入了 mybatis-plus-boot-starter 后,我们可以从依赖中找到对应的 jar 包,我们打开 jar 包可以找到一个关键的 MybatisPlusAutoConfiguration 配置文件,如下图所示 👇

在这里插入图片描述

在这里插入图片描述

熟悉 @Configuration 和 @Bean 这两个注解的小伙伴们或许已经明白了。这两个注解一起使用就可以创建一个可以替代 xml 配置文件的配置类。添加了 @Configuration 注解的类可以看作是能让 Spring IOC 容器管理的 Bean 实例的工厂。@Bean 注解可以告诉 Spring,带有 @Bean 的注解方法将返回一个对象,并且该对象需要被注册到 Spring 容器中。所以上面的 MybatisPlusAutoConfiguration 配置类,自动帮我们生成了 sqlSessionFactory 等重要的实例并将他们交给 Spring 容器管理,从而完成 Bean 的自动注册。

🍊 ② 自动配置条件依赖 🍊

在这里插入图片描述 通过 MybatisPlusAutoConfiguration 配置文件中添加的 @ConditionalOnClass 和 @ConditionalOnSingleCandidate 注解可以发现,需要完成自动配置是有依赖条件的,即需要在当前类的路径上存在 SqlSessionFactory.class 和 SqlSessionFactoryBean.class,同时需要存在已完成自动注册的 DataSource Bean,才可以完成自动配置。

这里我们顺便再说几个特殊的注解 👇

  • @ConditionalOnBean:当容器中有指定Bean的条件下进行实例化。
  • @ConditionalOnMissingBean:当容器里没有指定Bean的条件下进行实例化。
  • @ConditionalOnClass:当classpath类路径下有指定类的条件下进行实例化。
  • @ConditionalOnMissingClass:当类路径下没有指定类的条件下进行实例化。
  • @ConditionalOnWebApplication:当项目是一个Web项目时进行实例化。
  • @ConditionalOnNotWebApplication:当项目不是一个Web项目时进行实例化。
  • @ConditionalOnProperty:当指定的属性有指定的值时进行实例化。
  • @ConditionalOnExpression:基于SpEL表达式的条件判断。
  • @ConditionalOnJava:当JVM版本为指定的版本范围时触发实例化。
  • @ConditionalOnResource:当类路径下有指定的资源时触发实例化。
  • @ConditionalOnJndi:在JNDI存在的条件下触发实例化。
  • @ConditionalOnSingleCandidate:当指定的Bean在容器中只有一个,或者有多个但是指定了首选的Bean时触发实例化。

🍊 ③ Bean 参数获取 🍊

要完成 mybatis-plus 的自动配置,需要在配置文件中提供相关的配置参数,我们可以看到 MybatisPlusAutoConfiguration 配置文件中还写上了 @EnableConfigurationProperties 注解 👇

在这里插入图片描述

我们继续追踪源码,打开 MybatisPlusProperties.class 文件后可以发现,这个类上写着 @ConfigurationProperties 注解,这个注解的作用就是把 .yml 文件或者 .properties 配置文件中的配置参数信息封装到 @ConfigurationProperties 注解标注的 Bean (即 MybatisPlusProperties )的相应属性上,而 @EnableConfigurationProperties 注解的作用则是使 @ConfigurationProperties 注解生效。

在这里插入图片描述

🍊 ④ Bean 的发现 🍊 SpringBoot 默认扫描启动类所在的包下的主类与子类的所有组件,但并没有包括依赖包中的类,那么依赖包中的 Bean 又是如何被发现和加载的呢?下面我们就需要从 SpringBoot 项目的启动类开始跟踪了,在启动类上我们一般会加上 @SpringBootApplication 注解,源码如下 👇

在这里插入图片描述 我们都知道 @SpringBootApplication 主要是由三个注解构成:

  1. @SpringBootConfiguration:作用就相当于 @Configuration 注解,被添加了注解的类将成为一个Bean 配置类
  2. @ComponentScan:作用就是自动扫描并加载符合条件的组件,最终将这些 Bean 加载到 Spring 容器中
  3. @EnableAutoConfiguration :借助 @Import 注解的支持,收集和注册依赖包中相关的 Bean

接下来我们再看看 @EnableAutoConfiguration 注解 👇

在这里插入图片描述 我们可以发现 @EnableAutoConfiguration 注解又引入了 @Import 注解。导入了 AutoConfigurationImportSelector.class,AutoConfigurationImportSelector.class 源码如下 👇

在这里插入图片描述 我们在 AutoConfigurationImportSelector.class 源码中可以发现,getCandidateConfigurations 方法中调用了 SpringFactoriesLoader 类的 loadFactoryNames 方法,我们继续跟踪源码👇

在这里插入图片描述 关键的一行代码出现了,getResources 方法中调用了一个名为 FACTORIES_RESOURCE_LOCATION 的静态变量,这个静态变量对应的值就是 META-INF/spring.factories

在这里插入图片描述 看到这里,相信各位小伙伴应该已经清楚了,SpringFactoriesLoader 的 loadFactoryNames 静态方法可以从所有的 jar 包中读取 META-INF/spring.factories 文件,我们回过头再看一下 mybatis-plus-boot-starter 依赖,可以发现在 mybatis-plus-boot-starter 依赖中的 spring.factories 配置文件里有这样两行配置。也正是通过这个配置,可以让 SpringBoot 加载到 MybatisPlusAutoConfiguration 配置类了。 👇

在这里插入图片描述 🍊 ⑤ Bean 的加载 🍊

通过第四步的讲解,相信各位小伙伴也理解了 Bean 的加载流程,SpringBoot 使用 @Import 注解实现了自动配置,从 META-INF/spring.factories 文件中读取到的主配置文件的全类名,这样 SpringBoot 就可以加载到主配置文件中涉及到的 Bean 并完成实例的创建工作。

starter 的关键构成要素

通过上面的讲解,我们可以总结出构成 starter 的几个关键要素 👇

在这里插入图片描述

俗话说,要把大象装冰箱一共分为三步,那么如果自己需要开发一个 starter 一共分为几步呢?没错~~ 也是三步,最后我们来总结一下开发 starter 的三个步骤:

🍇 创建一个名为 xxx-xxx-boot-starter的空项目,并在pom.xml文件里引入自己所需的依赖。
🍇 开发自己所需的业务逻辑,业务开发完成后创建名为 xxxAutoConfiguration(或 xxxConfiguration) 的主配置类,在该类下定义一些所需的 Bean 实例
🍇 创建 spring.factories 配置文件,并在配置文件中引入主配置类org.springframework.boot.autoconfigure.EnableAutoCoinfiguration=xxx.xxx.xxx.xxxAutoConfiguration(或 xxxConfiguration)

小结

本人经验有限,有些地方可能讲的没有特别到位,如果您在阅读的时候想到了什么问题,欢迎在评论区留言,我们后续再一一探讨🙇‍

希望各位小伙伴动动自己可爱的小手,来一波点赞+关注 (✿◡‿◡) 让更多小伙伴看到这篇文章~ 蟹蟹呦(●'◡'●)

如果文章中有错误,欢迎大家留言指正;若您有更好、更独到的理解,欢迎您在留言区留下您的宝贵想法。

爱你所爱 行你所行 听从你心 无问东西