如何写自己的springboot starter?自动装配原理是什么?

news/2025/3/19 0:50:04/文章来源:https://www.cnblogs.com/isyues/p/18777524

如何写自己的springboot starter?自动装配原理是什么?

官方文档地址:https://docs.spring.io/spring-boot/docs/2.6.13/reference/html/features.html#features.developing-auto-configuration

1. 不用starter有什么弊端?

  • 我们开发需要引入maven依赖,如果我们需要的依赖又有它自身所需要的依赖。我们需要同时去引入才能去使用,这种模式让我们苦不堪。例如要在项目中使用 Spring Data JPA 进行数据库操作,需要手动添加 Spring Data JPA、Hibernate、数据库驱动等相关依赖,这不仅需要开发者了解每个依赖的具体信息,还容易出现版本不兼容的问题,因为不同版本的依赖之间可能存在冲突。
  • 配置麻烦,在SSM时期,大量的配置让我们晕头转向,没有starter的自动配置功能,需要手动编写大量的配置类和配置文件来启用和配置各种功能。例如,配置 Spring Data JPA 时,需要手动配置数据源、实体管理器工厂、事务管理器等
  • 如果另一个项目也需要同时去做同样的功能,如果不用starter只能使用CV大法把之前配置的都移过来,CV有可能出错,也让项目臃肿。

针对以上缺点,starter诞生它只需要引入一个依赖,搞定!

常见的starter例如:

spring-boot-starter
spring-boot-starter-web
spring-boot-starter-test
spring-cloud-starter-alibaba-nacos-discovery
druid-spring-boot-starter

2. springboot自动装配

要想自定义一个starter就要知道springboot是怎么样自动装配bean的

2.1 核心注解:

  • @SpringBootApplication:这是一个组合注解,相当于同时使用了 @Configuration、@EnableAutoConfiguration 和 @ComponentScan 注解。它标记了主应用程序类,并告诉 Spring Boot 开始组件扫描、自动配置和装配。
  • @EnableAutoConfiguration:该注解用于启用 Spring Boot 的自动配置功能。它会根据应用程序的依赖关系和当前环境,自动注册所需的 bean。
  • @ComponentScan:该注解用于启用组件扫描,以便 Spring Boot 可以自动发现和注册标有 @Component、@Service、@Repository 和 @Controller 注解的类。
  • @ConditionalOnClass 和 @ConditionalOnMissingClass:这两个条件化注解用于根据类路径上是否存在特定的类来决定是否注册 bean。@ConditionalOnClass 在类路径上存在指定类时生效,而 @ConditionalOnMissingClass 在类路径上不存在指定类时生效。
  • @ConditionalOnBean 和 @ConditionalOnMissingBean:这两个条件化注解用于根据是否存在特定的 bean 来决定是否注册 bean。@ConditionalOnBean 在容器中存在指定的 bean 时生效,而 @ConditionalOnMissingBean 在容器中不存在指定的 bean 时生效。
  • @ConditionalOnProperty:该条件化注解用于根据配置属性的值来决定是否注册 bean。它可以根据配置文件中的属性值来决定是否启用或禁用特定的 bean。

tips: 如果官方给你的注解不够满足需求可以自己创建一个Conditional,@Conditional(value = TestCondition.class)

public class TestCondition implements Condition {@Overridepublic boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {return true;}
}

2.2 自动装配大白话

  1. springboot启动类注解@SpringBootApplication是一个组合注解 里面包含了@EnableAutoConfiguration,即开启自动装配
  2. @Import(AutoConfigurationImportSelector.class),导入AutoConfigurationImportSelector,并通过 selectImports 方法读取 META-INF/spring.factories 文件中配置的全类名
    tips: 从spring boot2.7开始,慢慢不支持META-INF/spring.factories文件了需要导入的自动配置类可以放在
    /META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
  3. 并按照@ConditionalOnClass这样条件过滤的注解,如果满足条件注入bean

3. starter前知

3.1 取名该怎么样取?

spring官方文档上是这样说的 https://docs.spring.io/spring-boot/docs/2.0.0.M5/reference/htmlsingle/#boot-features-custom-starter-naming
image
翻译:

请确保为启动器提供合适的名称空间。不要以spring-boot作为模块名的开头,即使您使用的是不同的Maven groupId。我们可能会在将来为您自动配置的东西提供官方支持。
这是一条经验法则。假设您正在为“acme”创建一个启动器,将自动配置模块命名为acme-spring-boot-autoconfigure,将启动器命名为acme-spring-boot-starter。如果只有一个模块结合了这两个模块,那么使用acme-spring-boot-starter。
此外,如果启动器提供了配置键,请为它们使用适当的名称空间。特别是,不要在Spring Boot使用的命名空间(例如server、management、Spring等)中包含键。这些都是“我们的”,我们可能会在将来改进/修改它们,这样可能会破坏你的东西。
确保触发元数据生成,以便也为您的键提供IDE帮助。您可能需要查看生成的元数据(META-INF/spring-configuration-metadata.json),以确保正确地记录了密钥。

一般来说取名 xxx-spring-boot-starter就可以了

3.2 starter项目目录介绍

image

  • maven.spring-cloud-starter-alibaba-nacos-discovery
    这个是有关于maven的文件
  • additional-spring-configuration-metadata.json
{"properties": [{"name": "spring.cloud.loadbalancer.nacos.enabled","type": "java.lang.Boolean","defaultValue": false,"description": "Integrate LoadBalancer or not."}
]}

这个文件是配置元数据,很多时候我们可能会不知道这个starter有哪些是可以配置的,就可以来找这个文件,name就是属性名,defaultValue是默认值,description是描述。idea中配置文件里的补全提示也是读取这里的进行提示

  • MANIFEST.MF
    该文件包含了该 JAR 包的版本、创建人和类搜索路径等信息。
  • spring.factories
    spring.factories文件里的内容就是我们需要自启动装配的bean全路径
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure

官方tips:不要让这些类被组件扫描到
image

还有一些另外可能出现的键

org.springframework.boot.autoconfigure.EnableAutoConfiguration:用于自动配置类
org.springframework.context.ApplicationContextInitializer:应用上下文初始化器org.springframework.context.ApplicationListener:应用事件监听器
org.springframework.boot.SpringApplicationRunListener:应用运行监听器
org.springframework.boot.env.PropertySourceLoader:属性源加载器
org.springframework.boot.diagnostics.FailureAnalyzer:失败分析器
org.springframework.boot.env.EnvironmentPostProcessor:环境后处理器
org.springframework.boot.autoconfigure.AutoConfigurationImportFilter:自动配置导入过滤器
org.springframework.boot.autoconfigure.AutoConfigurationPackage:自动配置包

4. 实战需求来了

要实现一个starter,打印请求详细信息。

  1. 创建request-log-spring-boot-starter项目,打包方式为jar,引入依赖
<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><scope>provided</scope> <!-- 确保不重复引入 --></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-configuration-processor</artifactId><optional>true</optional> <!-- 生成配置元数据 --></dependency></dependencies>
  1. 创建RequestLogProperties类读取配置文件
@ConfigurationProperties(prefix = "request-log")
public class RequestLogProperties {private boolean enabled = true; // 是否启用日志private boolean logHeaders = true; // 是否记录请求头private boolean logBody = false; // 是否记录请求体(默认关闭,可能影响性能)public boolean isEnabled() {return enabled;}public void setEnabled(boolean enabled) {this.enabled = enabled;}public boolean isLogHeaders() {return logHeaders;}public void setLogHeaders(boolean logHeaders) {this.logHeaders = logHeaders;}public boolean isLogBody() {return logBody;}public void setLogBody(boolean logBody) {this.logBody = logBody;}
}
  1. resources下新建META-INF文件夹
  2. META-INF文件夹下新建spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\org.example.config.RequestLogAutoConfiguration

RequestLogAutoConfiguration类被spring.factories引入不需要@Configuration注解了

  1. 编写RequestLogAutoConfiguration类,加入条件判断
@ConditionalOnProperty(name = "request-log.enable", matchIfMissing = true)
@EnableConfigurationProperties(RequestLogProperties.class)
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
  1. 写RequestLoggingFilter类继承OncePerRequestFilter实现doFilterInternal进行业务逻辑
  2. 完工,测试

5. 代码提交到git上了:

https://gitee.com/isyuesen/request-log/tree/main/-

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/901190.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

清理 node.js 包管理工具 npm 的缓存

清理 node.js 包管理工具 npm 的缓存清理 node.js 包管理工具 npm 的缓存 要清理 Node.js 包管理工具 npm 的缓存,可以按照以下步骤操作。npm 的缓存主要用于存储下载的包,通常位于用户主目录下的 .npm 文件夹中。以下是清理方法: 1. 检查 npm 缓存位置 npm 默认将缓存存储在…

清理 Python 包管理工具 pip 的缓存

清理 Python 包管理工具 pip 的缓存清理 Python 包管理工具 pip 的缓存 要清理 pip 的缓存,可以按照以下步骤操作(适用于 Python 的包管理工具 pip):检查 pip 缓存位置 pip 默认会将下载的包缓存在本地。你可以通过以下命令查看缓存目录: pip cache dir常见的缓存路径:Wi…

清理 Python 的包管理工具 pip 的缓存

清理 Python 的包管理工具 pip 的缓存清理 Python 的包管理工具 pip 的缓存 要清理 pip 的缓存,可以按照以下步骤操作(适用于 Python 的包管理工具 pip):检查 pip 缓存位置 pip 默认会将下载的包缓存在本地。你可以通过以下命令查看缓存目录: pip cache dir常见的缓存路径…

微服务的网关配置

微服务的网关配置 1. 网关路由 1.1 网关 1.1.1 存在问题 单体架构时我们只需要完成一次用户登录、身份校验,就可以在所有业务中获取到用户信息。而微服务拆分后,每个微服务都独立部署,这就存在一些问题:每个微服务都需要编写身份校验、用户信息获取的接口,非常麻烦。 用户…

博客图床 VsCode + PigGo + 阿里云OSS方案

关键字 写博客,图床,VsCode,PigGo,阿里云OSS 背景环境 我想把我在本地写的markdown文档直接搬到CSDN上和博客园上,但是图片上传遇到了问题。我需要手动到不同平台上传文件,非常耗费时间和经历。 为了解决这个问题,我想到了图床方案,我只需要把图片链接放到我本地写好的…

20244203张晨曦 实验一《Python程序设计》实验报告

20244203张晨曦《Python程序设计》实验一报告 课程:《Python程序设计》 班级: 2442 姓名: 张晨曦 学号:20244203 实验教师:王志强 实验日期:2025年3月18日 必修/选修: 专选课 1.实验内容 1.熟悉Python开发环境; 2.练习Python运行、调试技能; 3.编写程序,练习变量和…

Cobalt Strike基础

Cobalt Strike基础 Staged(有阶段) 在有阶段的执行方式中,分为Stager和Stage两个阶段Stager(初始执行载荷):​ 定义:Stager是Stage 1,是一个较小的、轻量级的初始执行载荷 ​ 作用:与服务端建立初始连接,并从服务器下载更大的Payload,也就是Stage2Stage(更大、…

OP222柔性振动白色料盘污染会引发的问题

下图为污损的料盘料盘污损会导致以下问题: 1.料盘里面缺料但是后面料仓就是不送料 柔性振动系统里面设置了加料个数,下图里面设置为15,表示如果相机识别区域里面的总阴影面积<15个零件面积,料仓加一次料。下图红框是识别区域,里面一道道横杠就是污损导致的阴影,这些阴…

鸿蒙特效教程05-鸿蒙很开门特效

鸿蒙特效教程05-鸿蒙很开门特效本教程适合HarmonyOS初学者,通过简单到复杂的步骤,通过层叠布局 + 动画,一步步实现这个"鸿蒙很开门"特效。本教程能收获Stack 层叠布局 animate、animateTo 动画 @State 状态管理最终效果预览 屏幕上有一个双开门,点击中间的按钮后…

An Elder Brother Is Like a Father :My True Story

![](https://img2024.cnblogs.com/blog/3617180/202503/3617180-20250318230914275-242579668.jpg)An Elder Brother Is Like a Father :My True Story In your life, do you have a very important person? Who is he/she? Why is he/she significant for you and whats you…

element-plus学习 -2025/3/18

{ ...this.form } 是 JavaScript 中的 ​扩展运算符(Spread Operator)​,它的作用是将 this.form 对象的所有属性“展开”到一个新的对象中 例如 form :{ name : , score: } 简易学生分数管理系统 element-plus实现 <!DOCTYPE html> <html lang="en">…

web161笔记(getimagesize()图片文件头检测)

这次上传失败了,尝试在头部加了图片文件头,就过去了,所以这里应该是用了getimagesize()进行检测getimagesize(): 会对目标文件的16进制去进行一个读取,去读取头几个字符串是不是符合图片的要求所以在上题的基础上都加个GIF89a图片头就可以了 GIF89a加个图⽚的头欺骗检测 .u…