news 2026/7/17 6:00:56

SpringBoot制作Starter以及bean的自动装配

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
SpringBoot制作Starter以及bean的自动装配

什么是 Starter?

举个例子,在 Spring Boot 项目中引入 spring-boot-starter-data-redis 的依赖,就获得了一个全局可用的 StringRedisTemplate 类型的 bean 对象。

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

从命名上就能看出来,spring-boot-starter-data-redis 就是一个 starter。

当然,其实 spring-boot-starter-data-redis 并不是只有 StringRedisTemplate 这么一个 bean。

在 starter 中可以声明多个 bean,项目在启动的时候会加载需要的 bean,这个就是 bean 的自动装配。

在我的理解中,starter 就是一个 jar 包,只需要遵循 Spring 的约定大于配置的哲学,根据 Spring 的规则制作 jar 包。在其他项目中引入这个 jar 包就可以直接获得 bean 对象了,不需要二次配置。

如何制作自己的 starter?

官方自己制作的 starter 的命名规范是:spring-boot-starter-xxx。

  • spring-boot-starter-web
  • spring-boot-starter-data-redis
  • spring-boot-starter-mail

第三方制作 starter 的命名建议是:xxx-spring-boot-starter,跟官方命名的方向相反。

  • mybatis-spring-boot-starter

如果是自己制作的话,不用管那么多规范,因为蒙多想去哪就去哪。

第一步:创建新项目,引入依赖

<groupId>org.example</groupId> <artifactId>a</artifactId> <version>1.0-SNAPSHOT</version> <properties> <maven.compiler.source>17</maven.compiler.source> <maven.compiler.target>17</maven.compiler.target> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-autoconfigure</artifactId> <version>3.0.0</version> </dependency> </dependencies>

第二步:从配置文件获取数据

还是以 spring-boot-starter-data-redis 为例,我们在引入 jar 包后,需要在配置文件中配置 redis 的相关信息。

同样的,我们制作 starter 的时候也可以从配置文件中获取数据。prefix = "a",配置文件需要以 a 为前缀。

@ConfigurationProperties(prefix = "a") public class AProperties { private String A1; private String A2; public AProperties() { } public AProperties(String a1, String a2) { A1 = a1; A2 = a2; } public String getA1() { return A1; } public void setA1(String a1) { A1 = a1; } public String getA2() { return A2; } public void setA2(String a2) { A2 = a2; } }

第三步:编写业务类

public class AService { private AProperties aProperties; public AService(AProperties aProperties) { this.aProperties = aProperties; } public void work() { System.out.println("用户名:" + aProperties.getA1()); System.out.println("密码:" + aProperties.getA2()); System.out.println("starter业务执行"); } }

这里简单提供了一个 work 方法,打印 A1、A2 对应的取值,用来模拟从配置文件中获得地址、用户名、密码、数据库等信息。

第四步:编写自动配置类

@Configuration @EnableConfigurationProperties(AProperties.class) public class AAutoConfig { @Bean public AService aService(AProperties aProperties) { return new AService(aProperties); } }

在这个自动配置类中通过方法返回一个 bean 对象。

第五步:服从 Spring 的命令

在 resources 目录下创建 META-INF 目录。

在 META-INF 目录下创建 spring 目录。

在 spring 目录下创建 org.springframework.boot.autoconfigure.AutoConfiguration.imports 文件。

在这个什么 imports 文件中写入自动配置类的全类名。

org.example.a.AAutoConfig

这个是 Spring Boot 3 的写法,还有一种写法是 Spring Boot 2.x 的,但是我都没用过 2.x 的版本所以我也不知道怎么写。

但是写法本身不重要,也没必要研究茴香豆的茴字有多少种写法,要用的时候查一下就行了。

第六步:打 jar 包并保存到本地仓库

通过 maven 执行 install 命令,将项目打成 jar 包并保存到本地仓库中。

如果是用 IDEA 写 Java 的话,IDEA 本身就集成了 maven,就算自己安装了 maven 也会默认用 IDEA 自带的 maven,仓库目录是:C:\Users\admin\.m2\repository。

验证 starter 是否可正常使用

创建新项目,引入 starter。

<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <version>3.0.0</version> </dependency> <dependency> <groupId>org.example</groupId> <artifactId>a</artifactId> <version>1.0-SNAPSHOT</version> </dependency> </dependencies>
server: port: 8080 a: A1: 100 A2: 200
@RestController public class BController { @Autowired private AService aService; @GetMapping("/test") public int test() { aService.work(); return 200; } }

接口正常返回数据,业务方法正常执行。现在我们成功制作了一个自己的 starter,之后还需要用 AService 的功能,直接引入使用即可,可以说是开袋即食。

但是,我们这么大费周章,结果只是给 Spring 添加了一个 bean。我们不是可以用 @Component 注解声明 bean 吗?

那就试试吧。

@Component 和配置类

我在 starter 中添加了一个 bean。

@Component public class AComponent { public void work() { System.out.println("一个小组件"); } }

同时把 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 的目录和文件都删除掉了,确保 bean 的加载跟上文不同。

重新打包,这次把版本号改成 2.0-SNAPSHOT。

在测试项目中注入这个新的 bean。

@RestController public class BController { @Autowired private AService aService; @Autowired private AComponent aComponent; @GetMapping("/test") public int test() { aService.work(); aComponent.work(); return 200; } }

现在重新启动测试项目,结果服务启动失败,提示缺少 bean 对象。

Description: Field aComponent in org.example.b.BController required a bean of type 'org.example.a.AComponent' that could not be found. The injection point has the following annotations: - @org.springframework.beans.factory.annotation.Autowired(required=true) Action: Consider defining a bean of type 'org.example.a.AComponent' in your configuration.

为什么会出现这种情况呢?

因为 Spring 默认只会扫描启动类所在包和子包下面的类。我们的测试项目的包是 org.example.b,而 starter 项目的包是 org.example.a,在测试项目中根本就没有扫描到 org.example.a 下面的类,自然不会把 AComponent 注册为 bean。

解决方法很简单,在启动类中添加 @ComponentScan("org.example.a"),指定要扫描的路径即可。

@SpringBootApplication @ComponentScan("org.example.a") public class Main { public static void main(String[] args) { SpringApplication.run(Main.class, args); } }

现在服务启动成功了,但是接口报错了,响应码是 404。

这个问题就出在了 @ComponentScan("org.example.a") 这里,因为我们指定了要扫描路径是 org.example.a,所以它不会去扫描 org.example.b,我写的 Controller 都没有被扫描到,Controller 里面的 test 接口自然也不会开启。

浏览器向一个不存在的接口发送请求,当然是 404 资源不存在。

所以,我们需要继续修改要扫描的路径。

@SpringBootApplication @ComponentScan({"org.example.a", "org.example.b"}) public class Main { public static void main(String[] args) { SpringApplication.run(Main.class, args); } }

现在再启动项目试一下,这次就顺利启动并且接口正常响应了。

Spring Boot 中 bean 的自动装配

在我看来,bean 的创建有两种方式:

  • @Component 注解声明的 bean
  • @Configuration 配置类中 @Bean 方法返回的 bean

一个项目中 bean 的来源有两个途径:

  • 项目本身声明的 bean
  • 项目需要的依赖中引入的 bean

现在两两组合一下,得到了四种取值:

  • 项目自己通过 @Component 注解,被 @ComponentScan 扫描注册为 bean
  • 项目自己通过 @Configuration 配置类中 @Bean 注解,也是被 @ComponentScan 扫描注册为 bean
  • 依赖中的 @Component 注解,也需要被 @ComponentScan 扫描注册为 bean
  • 依赖中的配置类中的 @Bean 注解
    • 要么被 @ComponentScan 扫描注册为 bean
    • 要么遵循 Spring 的规则,创建 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 文件并写上配置类的全类名

如果是通过 @ComponentScan 扫描配置类的话,不需要这个 imports 文件。

但是,如果不用 @ComponentScan 的话,就必须用 imports 文件声明配置类的位置。

在 Spring Boot 的启动类中,有一个 @SpringBootApplication 注解,Ctrl + B 进入这个类,发现这个类上面还有其他注解。

  • @SpringBootApplication
    • @SpringBootConfiguration:这是一个配置类
    • @ComponentScan:扫描的路径,默认是扫描启动类所在包及其下面的子包
    • @EnableAutoConfiguration:从依赖中的 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 文件中获取自动配置类的路径,根据 @Conditional 注解这些配置类中的 @Bean 修饰的方法的返回值注册成 bean

那现在问题出现了,如果我们要用其他第三方的 bean,通过 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 这个文件只能获得配置类中 @Bean 方法返回的 bean,不能获得 @Component 声明的 bean。

如果要获得 @Component 声明的 bean,需要配置 @ComponentScan 的路径,但是我们一配置这个路径,就能直接获得 @Component 和 @Bean 声明的 bean 了,也不需要这个 imports 文件了啊。

其实直接通过 @ComponentScan 去指定路径的话是比较麻烦的。用极限法来假设一下,你要用 1000 亿个依赖,每个依赖都有自己的包名,那不就要在 @ComponentScan 中手动填写 1000 亿次?这多麻烦啊。

用 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 声明配置类的位置,这个工作不是我们自己干的,是制作这个依赖的人去完成的,我们只需要引入依赖就可以使用了,这就很方便。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/17 6:00:37

告别“小病大修”:当物流车队掌握话语权,商用车后市场如何重构?

长期以来&#xff0c;商用车后市场被贴上了“大而不强”、“散乱杂差”的标签。在这个万亿级的庞大市场中&#xff0c;充斥着大量缺乏标准的“夫妻老婆店”和价格不透明的维修乱象。然而&#xff0c;随着中国物流运输行业从追求规模扩张的“上半场”&#xff0c;步入深耕运营效…

作者头像 李华
网站建设 2026/7/17 5:59:53

STM32 PWM蓝牙无线调光实战:从原理到物联网应用

在实际嵌入式开发和硬件控制项目中&#xff0c;PWM&#xff08;脉冲宽度调制&#xff09;是一种基础且强大的信号调制技术&#xff0c;它通过调节脉冲的占空比来控制平均电压&#xff0c;从而实现对电机速度、LED亮度、舵机角度等设备的精确控制。而“bule”这个关键词&#xf…

作者头像 李华
网站建设 2026/7/17 5:59:32

GTA5线上小助手:洛圣都自由穿梭的终极导航器

GTA5线上小助手&#xff1a;洛圣都自由穿梭的终极导航器 【免费下载链接】GTA5OnlineTools GTA5线上小助手 项目地址: https://gitcode.com/gh_mirrors/gt/GTA5OnlineTools 在广阔的洛圣都世界中&#xff0c;距离和时间往往是完成任务的最大障碍。GTA5线上小助手为你提供…

作者头像 李华
网站建设 2026/7/17 5:59:29

Perl 5安全编程实践:从代码审计到漏洞防护的完整指南

1. 项目概述&#xff1a;为什么Perl 5的安全编程在今天依然至关重要&#xff1f;提起Perl&#xff0c;很多新入行的开发者可能会觉得它是一门“古老”的语言&#xff0c;甚至在一些讨论中&#xff0c;它已经被贴上了“过时”的标签。但如果你深入运维、自动化、文本处理或者一些…

作者头像 李华
网站建设 2026/7/17 5:56:59

Zed 的搜索体验进化:从“光标猜词“到“记忆优先“

背景 Zed 近期的一项新特性解决了一个看似微小却每天都在折磨开发者的问题&#xff1a;当你用文本查找器定位到某个匹配项、编辑完文件、再重新打开查找器时&#xff0c;上一次的搜索词丢失了——取而代之的往往是光标下某个毫不相干的单词。这次改进的核心&#xff0c;是重新排…

作者头像 李华