news 2026/4/19 20:00:31

Spring Boot 手写 Starter 实战:带开关 + 自动装配 + 日志模块

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Spring Boot 手写 Starter 实战:带开关 + 自动装配 + 日志模块

一、前言

很多人学 Spring Boot 时,会用各种 starter:

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

但用久了,容易产生一个误区:

觉得 starter 就是“一个依赖包”。

其实不是。

starter 真正的核心是:

引入依赖后,Spring Boot 能根据条件,自动把你需要的 Bean 装配进容器。

这篇文章,我们就从 0 手写一个最小可运行版 starter,做一个日志模块,并支持配置开关。

最终效果是:

业务项目只要引入依赖,并配置:

ark.logging.enabled: true

就能直接注入并使用:arkLogger.info("用户注册成功");


二、最终目标

我们要做两个模块:

ark-parent
├── ark-logging-spring-boot-starter
└── demo-app

其中:

  • ark-logging-spring-boot-starter:我们自己写的 starter
  • demo-app:业务项目,用来测试 starter 是否自动生效

三、整体思路

starter 的核心流程其实很简单:

1. 定义配置类
2. 定义功能类(日志组件)
3. 定义自动配置类
4. 通过 AutoConfiguration.imports 注册自动配置类
5. 业务项目引入 starter 后自动生效

再配合:

  • @ConditionalOnProperty:配置开关控制
  • @ConditionalOnClass:类存在才生效
  • @ConditionalOnMissingBean:允许业务方覆盖默认实现

这就是 starter 的基本骨架。官方文档也是按这个思路描述自动配置的。


四、父工程 pom.xml

先创建父工程ark-parent

ark-parent/pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.ark</groupId> <artifactId>ark-parent</artifactId> <version>1.0.0-SNAPSHOT</version> <packaging>pom</packaging> <modules> <module>ark-logging-spring-boot-starter</module> <module>demo-app</module> </modules> <properties> <java.version>17</java.version> <spring-boot.version>4.0.5</spring-boot.version> <maven.compiler.source>${java.version}</maven.compiler.source> <maven.compiler.target>${java.version}</maven.compiler.target> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>${spring-boot.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> </project>

五、starter 模块实现


1. starter 模块 pom.xml

ark-logging-spring-boot-starter/pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>com.ark</groupId> <artifactId>ark-parent</artifactId> <version>1.0.0-SNAPSHOT</version> </parent> <artifactId>ark-logging-spring-boot-starter</artifactId> <name>ark-logging-spring-boot-starter</name> <dependencies> <!-- 自动配置基础依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-autoconfigure</artifactId> </dependency> <!-- 提供基础 starter 能力和日志能力 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <!-- 生成配置提示元数据,可选 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> <optional>true</optional> </dependency> </dependencies> </project>

2. 定义配置属性类

starter 一般都会提供配置项。

比如我们做一个:

  • ark.logging.enabled:是否启用
  • ark.logging.prefix:日志前缀

ArkLoggingProperties.java

package com.ark.logging.starter.properties; import org.springframework.boot.context.properties.ConfigurationProperties; @ConfigurationProperties(prefix = "ark.logging") public class ArkLoggingProperties { /** * 是否启用日志模块 */ private boolean enabled = false; /** * 日志前缀 */ private String prefix = "[ARK-LOG]"; public boolean isEnabled() { return enabled; } public void setEnabled(boolean enabled) { this.enabled = enabled; } public String getPrefix() { return prefix; } public void setPrefix(String prefix) { this.prefix = prefix; } }

3. 定义日志接口

先定义一个最简单的接口。

ArkLogger.java

package com.ark.logging.starter.core; public interface ArkLogger { void info(String message); void error(String message); }

4. 定义默认实现类

DefaultArkLogger.java

package com.ark.logging.starter.core; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class DefaultArkLogger implements ArkLogger { private static final Logger log = LoggerFactory.getLogger(DefaultArkLogger.class); private final String prefix; public DefaultArkLogger(String prefix) { this.prefix = prefix; } @Override public void info(String message) { log.info("{} {}", prefix, message); } @Override public void error(String message) { log.error("{} {}", prefix, message); } }

这里用的是slf4j日志接口,业务项目最终看到的效果就是:

[ARK-LOG] 用户注册成功


5. 定义自动配置类

这一步是 starter 的核心。

ArkLoggingAutoConfiguration.java

package com.ark.logging.starter.autoconfig; import com.ark.logging.starter.core.ArkLogger; import com.ark.logging.starter.core.DefaultArkLogger; import com.ark.logging.starter.properties.ArkLoggingProperties; import org.slf4j.Logger; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; @AutoConfiguration @ConditionalOnClass(Logger.class) @EnableConfigurationProperties(ArkLoggingProperties.class) @ConditionalOnProperty(prefix = "ark.logging", name = "enabled", havingValue = "true") public class ArkLoggingAutoConfiguration { @Bean @ConditionalOnMissingBean public ArkLogger arkLogger(ArkLoggingProperties properties) { return new DefaultArkLogger(properties.getPrefix()); } }

这几个注解要重点理解。

@AutoConfiguration

表示这是一个自动配置类。Spring Boot 会把它当作自动装配候选。

@ConditionalOnClass(Logger.class)

表示只有类路径中存在Logger.class时才生效。
这类条件注解是自动配置常见写法。

@EnableConfigurationProperties(ArkLoggingProperties.class)

把我们写的配置属性类注册进 Spring 容器,并绑定配置文件内容。

@ConditionalOnProperty(...)

表示只有配置了:

ark.logging.enabled: true

时,自动配置才生效。

官方文档和 API 都说明了:

@ConditionalOnProperty常用于按配置开关决定是否创建 Bean;

如果没有显式设置matchIfMissing=true,默认属性缺失时不会匹配。

@ConditionalOnMissingBean

表示如果业务项目自己已经定义了ArkLogger,那 starter 就不再重复创建默认 Bean。
这就是典型的“给默认实现,但允许用户覆盖”。


6. 注册自动配置类

在 starter 模块下创建文件:

src/main/resources/METAINF/spring/

org.springframework.boot.autoconfigure.AutoConfiguration.imports

内容如下:

com.ark.logging.starter.autoconfig.ArkLoggingAutoConfiguration

这一行非常关键。

Spring Boot 会从这个文件中读取自动配置类列表。
这是当前官方推荐机制。


六、demo-app 测试模块实现


1. demo-app 模块 pom.xml

demo-app/pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>com.ark</groupId> <artifactId>ark-parent</artifactId> <version>1.0.0-SNAPSHOT</version> </parent> <artifactId>demo-app</artifactId> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- 引入自定义 starter --> <dependency> <groupId>com.ark</groupId> <artifactId>ark-logging-spring-boot-starter</artifactId> <version>1.0.0-SNAPSHOT</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>

2. 启动类

DemoApplication.java

package com.example.demo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } }

3. 测试 Controller

TestController.java

package com.example.demo.controller; import com.ark.logging.starter.core.ArkLogger; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class TestController { private final ArkLogger arkLogger; public TestController(ArkLogger arkLogger) { this.arkLogger = arkLogger; } @GetMapping("/test/log") public String testLog() { arkLogger.info("调用了 /test/log 接口"); return "ok"; } }

4. application.yml 配置

demo-app/src/main/resources/application.yml

server: port: 8080 ark: logging: enabled: true prefix: "[ARK-DEMO]"

七、运行和测试

启动demo-app,访问:http://localhost:8080/test/log

返回: ok

控制台打印类似:

[ARK-DEMO] 调用了 /test/log 接口

这就说明:

  • starter 已经被引入
  • 自动配置类已经被识别
  • 条件匹配成功
  • ArkLoggerBean 已经自动注入成功

八、开关验证

现在把配置改成:

ark:
logging:
enabled: false

再次启动。

由于@ConditionalOnProperty不满足,ArkLoggerBean 不会创建。
这时TestController依赖注入会失败,项目启动也会报错。

这就说明:

你的 starter 开关确实生效了。


九、允许业务方覆盖默认实现

如果业务项目不想用 starter 默认日志实现,而想自定义,也可以。

比如在demo-app中自己写:

CustomLoggerConfig.java

package com.example.demo.config; import com.ark.logging.starter.core.ArkLogger; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class CustomLoggerConfig { @Bean public ArkLogger arkLogger() { return new ArkLogger() { private final Logger log = LoggerFactory.getLogger("CustomArkLogger"); @Override public void info(String message) { log.info("[CUSTOM] {}", message); } @Override public void error(String message) { log.error("[CUSTOM] {}", message); } }; } }

由于 starter 里用了:

@ConditionalOnMissingBean

所以此时不会再创建默认的DefaultArkLogger
业务项目会优先使用自己的实现。
这也是自动配置最经典的扩展方式之一。


十、starter 的底层本质

你要把这一套彻底理解透:

普通 jar 包

只是提供类和方法。

starter

不只是提供类,还提供:

  • 配置项
  • 自动配置类
  • 条件装配逻辑
  • 默认 Bean
  • 扩展覆盖能力

也就是说:

starter 的本质,是把“Bean 创建逻辑”从业务项目里抽走,交给 Spring Boot 按条件自动完成。


十一、几个常见坑

1. 忘记写AutoConfiguration.imports

这是最常见的问题。

如果没写这个文件,自动配置类根本不会被 Spring Boot 识别。


2.@ConditionalOnProperty配置写错

比如你写了:

@ConditionalOnProperty(prefix = "ark.logging", name = "enabled", havingValue = "true")

那配置必须是:

ark.logging.enabled=true

或者 yml 形式:

ark: logging: enabled: true

3. 不要在 starter 里乱用@ComponentScan

starter 最稳的方式,是:

  • 自动配置类里手动@Bean
  • 配合条件注解控制

不要搞一堆扫描,把不该装配的类也扫进去。


4.matchIfMissing

如果你想做到“默认开启”,可以这样写:

@ConditionalOnProperty( prefix = "ark.logging", name = "enabled", havingValue = "true", matchIfMissing = true )

但默认情况下,matchIfMissingfalse


十二、面试怎么讲

你以后面试说这段就很像样:

我写过一个自定义 Spring Boot starter。
使用@AutoConfiguration定义自动配置类,并通过AutoConfiguration.imports注册。
在自动配置类中结合@ConditionalOnProperty做功能开关,结合@ConditionalOnMissingBean允许业务方覆盖默认实现。
最终业务项目只需要引入依赖并配置开关,就可以自动获得日志组件能力。

这就不是“只会用注解”了。
这是你已经开始理解 Spring Boot 自动装配机制了。


十三、总结

这篇 starter 实战,你要记住的其实就 4 句话:

1. starter 不是普通工具包,它是自动装配包
2. 自动配置类是 starter 的核心
3. 条件注解决定 Bean 是否生效
4. AutoConfiguration.imports 决定 Spring Boot 能不能找到你的自动配置类

再压缩成一句话就是:

starter = 依赖 + 自动配置 + 条件装配 + 默认实现

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

RAG 只是权宜之计

在我第一个生产级 RAG 系统上线三个月后&#xff0c;我在晚上 11 点收到了告警。 一个企业客户的聊天机器人检索到了一条完全针对不同员工层级的 HR 政策。语言足够相似&#xff0c;以至于检索器认为匹配。实际上并没有。我花了两天时间调优&#xff0c;更小的分块、更大的重叠…

作者头像 李华
网站建设 2026/4/19 19:57:02

BMP位图格式深度解析:从1bit到32bit的存储奥秘与实战应用

1. BMP位图的前世今生 第一次接触BMP文件是在大学计算机图形学课上&#xff0c;当时教授拿着一个只有几十KB的黑白图标说&#xff1a;"这个小小的文件里藏着整个图形世界的密码。"这句话让我对BMP格式产生了浓厚兴趣。作为Windows系统的"元老级"图像格式&a…

作者头像 李华
网站建设 2026/4/19 19:54:23

Scapy实战:从ARP缓存投毒到中间人攻击的攻防演练

1. ARP协议与缓存投毒原理剖析 ARP&#xff08;Address Resolution Protocol&#xff09;是局域网通信的基础协议&#xff0c;它的作用就像现实生活中的电话簿&#xff0c;负责将IP地址转换成对应的MAC地址。每台设备都维护着一个ARP缓存表&#xff0c;记录着最近通信过的设备信…

作者头像 李华