这是一份非常详细、实用、通俗易懂,权威、全面的Spring Boot Starter 的指南。
目录
Spring Boot Starter 是什么?
- 1.1 核心目标:简化依赖管理和配置
- 1.2 传统 Spring 应用配置的痛点
- 1.3 Starter 如何解决痛点:约定大于配置
- 1.4 Starter 的本质:依赖的聚合器
Spring Boot Starter 的工作原理
- 2.1 自动配置 ($Auto-Configuration$) 的核心地位
- 2.2 spring-boot-autoconfigure 模块
- 2.3 @EnableAutoConfiguration 注解
- 2.4 META-INF/spring.factories 文件:自动配置的注册表
- 2.5 条件注解 ($Conditional Annotations$):按需配置的魔法
- @ConditionalOnClass
- @ConditionalOnMissingBean
- @ConditionalOnProperty
- @ConditionalOnWebApplication
- 其他条件注解
- 2.6 配置属性 ($Configuration Properties$):@ConfigurationProperties
如何使用官方提供的 Spring Boot Starter
- 3.1 在 pom.xml 中添加 Starter 依赖
- 3.2 理解 Starter 带来的依赖传递
- 3.3 自动配置生效的验证
- 3.4 覆盖自动配置:自定义 Bean 和属性配置
- 3.5 禁用特定的自动配置类
创建自定义 Spring Boot Starter
- 4.1 明确 Starter 的目的和功能
- 4.2 创建独立的 Starter 模块项目
- 4.3 定义 Starter 的核心功能库 (autoconfigure 模块最佳实践)
- 4.4 编写自动配置类 (AutoConfiguration)
- 使用条件注解控制配置生效
- 定义需要自动创建的 Bean
- 绑定配置属性 (@ConfigurationProperties)
- 4.5 注册自动配置类:创建 META-INF/spring.factories
- 4.6 提供 Starter 模块:聚合核心库和依赖
- 4.7 可选:提供额外的元数据 (spring-configuration-metadata.json)
- 4.8 打包和发布 Starter
最佳实践
- 5.1 Starter 设计原则:单一职责、开箱即用
- 5.2 谨慎使用自动配置:避免魔法过多
- 5.3 提供清晰、灵活的配置选项
- 5.4 完善的文档和示例
- 5.5 良好的命名规范 (xxx-spring-boot-starter)
实战案例 1:集成 Redis Starter
- 6.1 添加 spring-boot-starter-data-redis 依赖
- 6.2 配置 Redis 连接 (application.properties)
- 6.3 自动注入 RedisTemplate 和 StringRedisTemplate
- 6.4 编写示例代码:存储和读取数据
- 6.5 完整可运行代码示例
实战案例 2:集成 Spring Security Starter
- 7.1 添加 spring-boot-starter-security 依赖
- 7.2 默认安全配置的行为
- 7.3 自定义用户、密码和角色 (内存、JDBC、LDAP)
- 7.4 自定义安全配置 (@EnableWebSecurity, WebSecurityConfigurerAdapter)
- 7.5 示例:配置基于表单的登录和简单授权规则
- 7.6 完整可运行代码示例 (简化版)
实战案例 3:创建自定义 Starter – 简易短信发送 Starter
- 8.1 项目结构规划 (sms-spring-boot-starter, sms-spring-boot-autoconfigure)
- 8.2 sms-spring-boot-autoconfigure 模块开发
- 定义配置属性类 SmsProperties
- 编写自动配置类 SmsAutoConfiguration
- 创建 SmsSender 接口和默认实现 DefaultSmsSenderImpl
- 注册自动配置 (META-INF/spring.factories)
- 8.3 sms-spring-boot-starter 模块开发 (依赖 autoconfigure 和必要的库)
- 8.4 在另一个 Spring Boot 项目中使用自定义 Starter
- 添加自定义 Starter 依赖
- 配置短信参数 (application.yml)
- 自动注入 SmsSender 并发送短信
- 8.5 完整可运行代码示例 (包含 Starter 和使用项目)
1. Spring Boot Starter 是什么?
1.1 核心目标:简化依赖管理和配置 Spring Boot Starter 是 Spring Boot 框架的核心组件之一,其核心目标是极大地简化基于 Spring 框架的应用开发。它主要通过以下两种方式实现:
- 简化依赖管理: 将特定功能所需的一系列相关依赖库打包成一个可传递的依赖项。开发者只需引入这一个 Starter,即可获得开发该功能所需的所有常规库。
- 简化配置: 基于“约定大于配置”的理念,提供合理的默认配置。开发者通常只需要提供少量的必要配置(如数据库连接字符串),甚至零配置,就能让功能正常工作。
1.2 传统 Spring 应用配置的痛点 在传统的 Spring 应用开发中,集成一个新的功能(如数据库访问、安全、Web MVC)通常需要:
1.3 Starter 如何解决痛点:约定大于配置 Spring Boot Starter 解决了这些问题:
- 依赖打包: Starter 本身通常不包含代码,它只是一个 POM 文件 (pom.xml),声明了实现某个功能所需的一组依赖库及其兼容的版本。例如,spring-boot-starter-web 包含了 Spring MVC, Tomcat, Jackson 等开发 Web 应用所需的所有库。
- 自动配置: 这是 Starter 背后的魔法引擎。当 Starter 被引入到项目中,Spring Boot 的自动配置机制会根据项目中存在的类路径、已定义的 Bean 和其他设置,自动地配置 Spring 应用上下文。例如,如果类路径下有 DataSource 类,并且你没有自己定义一个 DataSource Bean,Spring Boot 会自动配置一个基于内存数据库(如 H2)或连接池(如 HikariCP)的 DataSource(取决于依赖和配置)。
1.4 Starter 的本质:依赖的聚合器 简单来说,Starter 就是一个预定义好的、针对特定功能的依赖项集合。 它让你只需声明一次“我想要 Web 功能”或“我想要 JPA 功能”,Spring Boot 就会为你准备好所有必要的库和默认配置。这极大地降低了入门门槛和配置复杂度。
2. Spring Boot Starter 的工作原理 Starter 的强大功能主要依赖于 Spring Boot 的自动配置机制。
2.1 自动配置 ($Auto-Configuration$) 的核心地位 自动配置是 Spring Boot 的核心特性。它尝试基于你添加的 jar 依赖和你的代码配置,自动配置你的 Spring 应用。例如:
- 如果 H2 数据库在类路径上,并且你没有配置自己的 DataSource Bean,那么 Spring Boot 会自动配置一个内存数据库。
- 如果 Spring MVC 在类路径上,Spring Boot 会自动配置一个 DispatcherServlet 和默认的 MVC 组件(视图解析器、消息转换器等)。
2.2 spring-boot-autoconfigure 模块 这个模块包含了 Spring Boot 为各种常见场景提供的自动配置实现。它内部定义了大量的 XxxAutoConfiguration 类。每个 Starter 通常都会依赖于这个模块,并可能提供自己特定的自动配置类。
2.3 @EnableAutoConfiguration 注解 Spring Boot 应用的入口类通常使用 @SpringBootApplication 注解。这个注解是一个组合注解,包含了 @EnableAutoConfiguration。正是 @EnableAutoConfiguration 启用了自动配置机制。它告诉 Spring Boot 去扫描类路径下的 META-INF/spring.factories 文件,查找并加载其中声明的自动配置类。
2.4 META-INF/spring.factories 文件:自动配置的注册表 这是自动配置的关键注册表文件。它位于 jar 包的 META-INF 目录下。文件内容遵循 Java 的 Properties 格式。其中最重要的键是:
org.springframework.boot.autoconfigure.EnableAutoConfiguration
该键的值是一个逗号分隔的、完全限定名的自动配置类列表。例如,spring-boot-autoconfigure jar 中的 spring.factories 包含大量条目:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\\
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\\
… // 很多很多其他配置类
当 Spring Boot 启动时,它会读取所有 jar 包中这个文件,收集所有的自动配置类。
2.5 条件注解 ($Conditional Annotations$):按需配置的魔法 Spring Boot 不会简单地加载 spring.factories 中列出的所有配置类。它使用条件注解来决定一个配置类(或配置类中的一个 @Bean 方法)是否应该生效。这确保了配置只在满足特定条件时被应用。常用的条件注解包括:
- @ConditionalOnClass:只有当指定的类存在于类路径上时,配置才生效。例如,DataSourceAutoConfiguration 可能只在检测到 DataSource 类存在时才生效。
- @ConditionalOnMissingBean:只有当 Spring 应用上下文中不存在指定类型的 Bean 时,配置才生效。这让你可以轻松地提供自己的实现来覆盖自动配置。例如,自动配置的 DataSource 可能只在没有用户定义的 DataSource Bean 时创建。
- @ConditionalOnProperty:只有当指定的环境属性(通常在 application.properties 或 application.yml 中)存在、缺失或具有特定值时,配置才生效。这提供了灵活的配置开关。例如,@ConditionalOnProperty(name = "spring.datasource.url") 确保只有配置了数据库 URL 时才尝试配置数据源。
- @ConditionalOnWebApplication:只有当应用是一个 Web 应用(基于 Servlet 或 Reactive)时,配置才生效。
- @ConditionalOnNotWebApplication:与上面相反。
- @ConditionalOnExpression:基于 SpEL 表达式的结果进行条件判断。
- @ConditionalOnJava:基于运行时的 Java 版本。
- @ConditionalOnResource:基于特定资源文件是否存在。
- @ConditionalOnSingleCandidate:当某个类型的 Bean 存在且是唯一候选(或主要候选)时生效。 这些注解通常组合使用在一个自动配置类或其 @Bean 方法上,精确控制配置的生效时机。
2.6 配置属性 ($Configuration Properties$):@ConfigurationProperties 自动配置通常需要读取外部配置(如 application.properties)。Spring Boot 提供了 @ConfigurationProperties 注解,用于将配置文件中的属性绑定到 Java Bean 上。这些属性 Bean 通常由自动配置类注入并使用。例如:
@ConfigurationProperties(prefix = "spring.datasource")
public class DataSourceProperties {
private String url;
private String username;
private String password;
// … getters and setters
}
在自动配置类中:
@AutoConfiguration
@EnableConfigurationProperties(DataSourceProperties.class)
public class DataSourceAutoConfiguration {
@Bean
@ConditionalOnMissingBean(DataSource.class)
public DataSource dataSource(DataSourceProperties properties) {
// 使用 properties.getUrl(), properties.getUsername() 等创建 DataSource
return …;
}
}
这样,用户只需在 application.properties 中设置 spring.datasource.url=…,这些值就会自动注入到 DataSourceProperties,进而用于创建 DataSource Bean。
3. 如何使用官方提供的 Spring Boot Starter
3.1 在 pom.xml 中添加 Starter 依赖 使用官方 Starter 非常简单。只需要在你的 Spring Boot 项目的 pom.xml 文件的 <dependencies> 部分添加所需的 Starter。命名约定通常是 spring-boot-starter-*。例如:
<!– 添加 Web 功能 (MVC, Tomcat, Jackson…) –>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!– 添加 JPA 和 Hibernate (假设使用 Hibernate) –>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!– 添加嵌入式 H2 数据库 –>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
Spring Boot 的依赖管理 (spring-boot-starter-parent 或 spring-boot-dependencies BOM) 会确保这些 Starter 及其传递依赖的版本是兼容的。
3.2 理解 Starter 带来的依赖传递 使用 mvn dependency:tree 命令可以查看添加 Starter 后引入的所有传递依赖。理解这些依赖有助于排查问题。
3.3 自动配置生效的验证 Spring Boot 应用启动时,会在日志中输出自动配置报告。将日志级别设置为 DEBUG (在 application.properties 中设置 logging.level.root=DEBUG) 可以查看更详细的报告。报告会列出:
- 评估了哪些自动配置类 (AutoConfiguration classes)。
- 哪些通过了条件注解 (Condition),因此被应用 (Positive matches)。
- 哪些没有通过条件注解 (Condition),因此没有被应用 (Negative matches)。
- 哪些因为排除等原因未被评估 (Exclusions)。 这是理解自动配置行为的重要工具。
3.4 覆盖自动配置:自定义 Bean 和属性配置 自动配置不是不可变的。你有两种主要方式来覆盖它:
3.5 禁用特定的自动配置类 如果你完全不想要某个自动配置生效,可以使用 @SpringBootApplication 或 @EnableAutoConfiguration 的 exclude 属性来禁用特定的自动配置类:
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class, SecurityAutoConfiguration.class})
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
或者在 application.properties 中:
spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration
4. 创建自定义 Spring Boot Starter 当你开发了一个可重用的 Spring 组件或集成库,并且希望它像官方 Starter 一样提供开箱即用的体验时,可以创建自定义 Starter。
4.1 明确 Starter 的目的和功能 清晰定义你的 Starter 要解决的问题、提供的核心功能以及所需的配置项。
4.2 创建独立的 Starter 模块项目 通常建议将 Starter 拆分成两个模块(使用 Maven 或 Gradle):
- yourmodule-spring-boot-autoconfigure:包含自动配置类 (XxxAutoConfiguration)、配置属性类 (XxxProperties)、条件注解(如果需要)以及核心功能接口/抽象。这是实现自动配置逻辑的地方。 它依赖 spring-boot-autoconfigure 和 spring-boot-configuration-processor (可选,用于元数据生成)。
- yourmodule-spring-boot-starter:这是一个空的或仅包含少量代码的模块。它的主要作用是提供一个方便的依赖项,用户只需引入这一个依赖。它依赖于 yourmodule-spring-boot-autoconfigure 模块,以及你的 Starter 功能所需的其他第三方库。命名遵循 xxx-spring-boot-starter 约定。 这种分离的好处是:
- 用户可以选择只依赖 autoconfigure 模块(如果他们需要更精细的控制)。
- 核心的自动配置逻辑与 Starter 的依赖管理解耦。
4.3 定义 Starter 的核心功能库 (autoconfigure 模块最佳实践) 在 autoconfigure 模块中,定义你的 Starter 需要自动配置的核心功能。这通常包括:
- 一个或多个自动配置类 (XxxAutoConfiguration)。
- 一个或多个配置属性类 (XxxProperties)。
- 提供核心功能的 Service 接口和默认实现类。
- 相关的工具类。
4.4 编写自动配置类 (AutoConfiguration) 这是 Starter 的核心。
- 类注解: 使用 @AutoConfiguration 注解标记你的类。这个注解继承自 @Configuration,并表明这是一个 Spring Boot 自动配置类。通常放在 xxx.auto 包下。
- 使用条件注解: 在类级别或 @Bean 方法级别大量使用条件注解 (@ConditionalOnClass, @ConditionalOnMissingBean, @ConditionalOnProperty 等) 来控制配置的生效条件。确保你的配置只在合适的环境下激活。
- 定义需要自动创建的 Bean: 在配置类中使用 @Bean 方法创建你的 Starter 需要提供的 Bean(如服务类、连接工厂、模板类等)。这些 Bean 通常是单例的。
- 绑定配置属性 (@ConfigurationProperties):
- 创建一个配置属性类,使用 @ConfigurationProperties(prefix = "your.prefix") 注解,并定义与你的配置项对应的字段及其 getter/setter。
- 在你的自动配置类上使用 @EnableConfigurationProperties(XxxProperties.class) 来启用该属性类。
- 在 @Bean 方法中,将 XxxProperties 作为参数注入,并使用其中的值来配置你创建的 Bean。
@AutoConfiguration // Spring Boot 2.7+ 推荐,替代 @Configuration
@ConditionalOnClass(SmsService.class) // 当 SmsService 在类路径上才生效
@EnableConfigurationProperties(SmsProperties.class) // 启用属性绑定
public class SmsAutoConfiguration {
@Bean
@ConditionalOnMissingBean // 只有当用户没有自定义 SmsSender 时才创建
public SmsSender smsSender(SmsProperties properties) {
// 使用 properties 中的配置 (如 apiKey, endpoint) 创建并配置一个默认的 SmsSender 实现
DefaultSmsSenderImpl sender = new DefaultSmsSenderImpl();
sender.setApiKey(properties.getApiKey());
sender.setEndpoint(properties.getEndpoint());
return sender;
}
}
4.5 注册自动配置类:创建 META-INF/spring.factories 为了让 Spring Boot 发现你的自动配置类,你需要在 autoconfigure 模块的 src/main/resources/META-INF/ 目录下创建一个名为 spring.factories 的文件。 文件内容如下:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\\
com.yourcompany.autoconfigure.sms.SmsAutoConfiguration
将你的自动配置类的全限定名添加到 EnableAutoConfiguration 键的值列表中。如果有多个,用逗号分隔。
4.6 提供 Starter 模块:聚合核心库和依赖 创建 yourmodule-spring-boot-starter 模块。它的 pom.xml 应该:
- 依赖 yourmodule-spring-boot-autoconfigure 模块。
- 依赖你的 Starter 功能实现所需的所有其他第三方库。这些库会被传递到使用 Starter 的项目中。
- 通常不包含代码或只包含极少的胶水代码。
<!– yourmodule-spring-boot-starter/pom.xml –>
<dependencies>
<dependency>
<groupId>com.yourcompany</groupId>
<artifactId>yourmodule-spring-boot-autoconfigure</artifactId>
<version>${project.version}</version>
</dependency>
<!– 依赖实际发送短信的 SDK 或库 –>
<dependency>
<groupId>com.example.sms</groupId>
<artifactId>sms-sdk</artifactId>
<version>1.0.0</version>
</dependency>
</dependencies>
4.7 可选:提供额外的元数据 (spring-configuration-metadata.json) 为了在用户使用 IDE(如 IntelliJ IDEA)或在 application.properties 中输入配置时获得自动补全和文档提示,你可以为你的配置属性生成元数据。
- 在 autoconfigure 模块中添加依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional> <!– 避免传递 –>
</dependency> - 在 XxxProperties 类上使用 @ConfigurationProperties,并确保字段有 Javadoc 注释。
- 构建项目 (mvn clean package)。构建过程会生成 target/classes/META-INF/spring-configuration-metadata.json 文件。将这个文件包含在你的 autoconfigure jar 包中。 这个 JSON 文件描述了配置属性的名称、类型、描述、默认值等信息。
4.8 打包和发布 Starter 像发布普通库一样,将 autoconfigure 模块和 starter 模块打包 (mvn clean install 或 mvn clean deploy 到 Maven 仓库)。用户只需要在他们的项目中依赖 yourmodule-spring-boot-starter 即可使用你的功能。
5. 最佳实践
- 5.1 单一职责: 一个 Starter 应该只负责集成一个特定的技术或提供一个特定的功能集。避免创建“大而全”的 Starter。
- 5.2 开箱即用: 提供合理的默认配置,使得用户在引入 Starter 后,仅需最少(甚至零)配置就能使用基本功能。默认配置应该适用于常见场景。
- 5.3 谨慎使用自动配置: 虽然自动配置很强大,但要避免“过度魔法”。确保你的配置逻辑清晰,并且用户能够轻松地理解、覆盖或禁用它。大量使用条件注解是控制的关键。
- 5.4 提供清晰、灵活的配置选项: 通过 @ConfigurationProperties 暴露足够的配置项,让用户能够定制 Starter 的行为。提供详尽的配置属性文档。
- 5.5 完善的文档和示例: 为你的 Starter 编写清晰的 README 文件,说明如何引入、基本用法、配置项列表以及常见问题。提供简单的示例项目。
- 5.6 良好的命名规范: 遵循社区约定,将你的 Starter 命名为 xxx-spring-boot-starter。将自动配置模块命名为 xxx-spring-boot-autoconfigure。
6. 实战案例 1:集成 Redis Starter 目标: 在 Spring Boot 项目中快速集成 Redis,使用 RedisTemplate 操作数据。
6.1 添加依赖 (pom.xml)
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!– 如果需要连接池 –>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
6.2 配置 Redis (application.properties)
# Redis 服务器地址
spring.redis.host=localhost
# Redis 服务器端口
spring.redis.port=6379
# Redis 数据库索引 (默认为0)
spring.redis.database=0
# 连接池配置 (使用 commons-pool2)
spring.redis.lettuce.pool.enabled=true # 如果使用 Lettuce (默认)
spring.redis.lettuce.pool.max-idle=8
spring.redis.lettuce.pool.min-idle=0
spring.redis.lettuce.pool.max-active=8
spring.redis.lettuce.pool.max-wait=-1ms
# 或者 Jedis (需要排除 Lettuce 依赖或配置 Jedis)
# spring.redis.jedis.pool.enabled=true
# … 类似配置
6.3 自动注入 RedisTemplate 和 StringRedisTemplate Spring Boot 的自动配置已经创建了这两个 Bean。
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/redis")
public class RedisController {
@Autowired
private RedisTemplate<String, Object> redisTemplate; // 操作对象
@Autowired
private StringRedisTemplate stringRedisTemplate; // 操作字符串
}
6.4 示例代码:存储和读取数据
@PostMapping("/set")
public String setValue(@RequestParam String key, @RequestParam String value) {
// 使用 StringRedisTemplate 存储字符串
stringRedisTemplate.opsForValue().set(key, value);
return "Value set successfully for key: " + key;
}
@GetMapping("/get")
public String getValue(@RequestParam String key) {
// 使用 StringRedisTemplate 读取字符串
String value = stringRedisTemplate.opsForValue().get(key);
return (value != null) ? value : "Key not found: " + key;
}
// 使用 RedisTemplate 存储对象 (需要对象可序列化)
@PostMapping("/setUser")
public String setUser(@RequestParam String key, @RequestBody User user) {
redisTemplate.opsForValue().set(key, user);
return "User set successfully for key: " + key;
}
@GetMapping("/getUser")
public User getUser(@RequestParam String key) {
return (User) redisTemplate.opsForValue().get(key);
}
注意: User 类需要实现 Serializable 接口。
6.5 完整可运行代码示例 (片段) 假设一个简单的 Spring Boot 应用入口:
@SpringBootApplication
public class RedisDemoApplication {
public static void main(String[] args) {
SpringApplication.run(RedisDemoApplication.class, args);
}
}
结合上面的 RedisController 和 User 类,运行应用后,可以使用 Postman 或 curl 测试 /redis/set, /redis/get, /redis/setUser, /redis/getUser 等端点。确保本地或配置的 Redis 服务器正在运行。
7. 实战案例 2:集成 Spring Security Starter 目标: 快速为 Spring Boot Web 应用添加基本的安全认证和授权。
7.1 添加依赖 (pom.xml)
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
7.2 默认安全配置的行为 引入 Starter 后,Spring Security 自动配置生效:
- 所有 HTTP 端点都需要认证。
- 自动生成一个随机密码的用户(用户名 user),密码打印在控制台日志中。
- 提供基于表单的登录和 HTTP Basic 认证。
- 提供注销功能。
- 保护 CSRF 攻击。
- 会话管理。
- 等等。
7.3 自定义用户、密码和角色 方法 1:内存用户 (演示用) 在 application.properties 中配置:
# 配置内存用户 (实际项目用数据库或LDAP)
spring.security.user.name=admin
spring.security.user.password=admin123
spring.security.user.roles=ADMIN,USER
方法 2:自定义 UserDetailsService (更灵活) 创建一个配置类实现 UserDetailsService:
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
@Override
public UserDetailsService userDetailsService() {
// 内存用户存储 (InMemoryUserDetailsManager)
UserDetails user = User.withDefaultPasswordEncoder()
.username("user")
.password("password")
.roles("USER")
.build();
UserDetails admin = User.withDefaultPasswordEncoder()
.username("admin")
.password("adminpass")
.roles("USER", "ADMIN")
.build();
return new InMemoryUserDetailsManager(user, admin);
}
// 注意:`withDefaultPasswordEncoder` 仅用于演示,生产环境必须使用加密!
}
7.4 自定义安全配置 (@EnableWebSecurity, WebSecurityConfigurerAdapter) 要自定义 URL 访问规则、登录页面等,需要扩展 WebSecurityConfigurerAdapter:
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/", "/home", "/public/**").permitAll() // 公共访问
.antMatchers("/admin/**").hasRole("ADMIN") // ADMIN 角色访问
.antMatchers("/user/**").hasRole("USER") // USER 角色访问
.anyRequest().authenticated() // 其他请求需要认证
.and()
.formLogin()
.loginPage("/login") // 自定义登录页路径
.permitAll() // 允许所有人访问登录页
.and()
.logout()
.permitAll(); // 允许所有人注销
}
// … 上面的 userDetailsService() Bean 定义 …
}
7.5 示例:配置基于表单的登录和简单授权规则 结合上面的 SecurityConfig,创建一个简单的登录页面 (login.html – 需要 Thymeleaf 或其他模板引擎):
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Login</title>
</head>
<body>
<div th:if="${param.error}">Invalid username or password.</div>
<form th:action="@{/login}" method="post">
<label>Username: <input type="text" name="username"/></label>
<label>Password: <input type="password" name="password"/></label>
<button type="submit">Login</button>
</form>
</body>
</html>
创建一个 HomeController 提供 /home, /login 等视图映射。
7.6 完整可运行代码示例 (简化版)
@SpringBootApplication
public class SecurityDemoApplication {
public static void main(String[] args) {
SpringApplication.run(SecurityDemoApplication.class, args);
}
}
@Controller
public class HomeController {
@GetMapping({"/", "/home"})
public String home() {
return "home"; // home.html
}
@GetMapping("/login")
public String login() {
return "login"; // login.html
}
@GetMapping("/admin")
@ResponseBody
public String adminPage() {
return "Admin Page";
}
@GetMapping("/user")
@ResponseBody
public String userPage() {
return "User Page";
}
}
// SecurityConfig 如上所示 (包含内存用户和 HTTP 安全配置)
运行应用,访问 /admin 会重定向到 /login。使用 admin/adminpass 登录后可以访问 /admin 和 /user。使用 user/password 登录后只能访问 /user。访问 /home 无需登录。
8. 实战案例 3:创建自定义 Starter – 简易短信发送 Starter 目标: 创建一个 Starter,让用户只需添加依赖并配置 API key/endpoint,就能自动注入一个 SmsSender Bean 用于发送短信。
8.1 项目结构 使用 Maven 创建两个模块:
- sms-spring-boot-autoconfigure (实现自动配置)
- sms-spring-boot-starter (依赖 autoconfigure 和短信 SDK)
8.2 sms-spring-boot-autoconfigure 模块开发
- pom.xml:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<!– 假设我们有一个简单的短信发送接口定义在这个模块里 –>
</dependencies> - SmsProperties.java (配置属性绑定):
@ConfigurationProperties(prefix = "sms")
public class SmsProperties {
private String apiKey;
private String endpoint = "https://api.smsprovider.com/send"; // 默认值
// … getters and setters
} - SmsSender.java (服务接口):
public interface SmsSender {
boolean send(String phoneNumber, String message);
} - DefaultSmsSenderImpl.java (默认实现 – 模拟):
public class DefaultSmsSenderImpl implements SmsSender {
private String apiKey;
private String endpoint;
// … getters and setters for apiKey and endpoint
@Override
public boolean send(String phoneNumber, String message) {
// 模拟发送逻辑,打印日志
System.out.println("Sending SMS to " + phoneNumber + ": " + message);
System.out.println("Using API Key: " + apiKey + ", Endpoint: " + endpoint);
return true; // 模拟成功
}
} - SmsAutoConfiguration.java (自动配置类):
@AutoConfiguration
@ConditionalOnClass(SmsSender.class) // 当 SmsSender 在类路径 (即本模块) 时生效
@EnableConfigurationProperties(SmsProperties.class)
public class SmsAutoConfiguration {
@Bean
@ConditionalOnMissingBean // 用户没有自定义时才创建
public SmsSender smsSender(SmsProperties properties) {
DefaultSmsSenderImpl sender = new DefaultSmsSenderImpl();
sender.setApiKey(properties.getApiKey());
sender.setEndpoint(properties.getEndpoint());
return sender;
}
} - src/main/resources/META-INF/spring.factories:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\\
com.example.sms.autoconfigure.SmsAutoConfiguration
8.3 sms-spring-boot-starter 模块开发
- pom.xml:
<dependencies>
<dependency>
<groupId>com.example.sms</groupId>
<artifactId>sms-spring-boot-autoconfigure</artifactId>
<version>1.0.0</version> <!– 匹配 autoconfigure 版本 –>
</dependency>
<!– 如果 DefaultSmsSenderImpl 使用了真实的 SDK,这里依赖它 –>
<!– <dependency>
<groupId>com.real.sms</groupId>
<artifactId>sms-sdk</artifactId>
<version>2.0.1</version>
</dependency> –>
</dependencies>注意: 在这个例子中,DefaultSmsSenderImpl 是我们自己写的模拟类,放在 autoconfigure 模块里了。如果使用第三方 SDK,需要在这里依赖它。
8.4 在另一个 Spring Boot 项目中使用自定义 Starter
- 添加依赖 (pom.xml):
<dependency>
<groupId>com.example.sms</groupId>
<artifactId>sms-spring-boot-starter</artifactId>
<version>1.0.0</version>
</dependency> - 配置参数 (application.yml):
sms:
api-key: "your_real_api_key_here" # 替换成真实 key
# endpoint: "https://custom.endpoint.com" # 可选,覆盖默认 - 自动注入 SmsSender 并发送短信:
@Service
public class OrderService {
private final SmsSender smsSender;
@Autowired
public OrderService(SmsSender smsSender) { // 自动注入
this.smsSender = smsSender;
}
public void placeOrder(Order order) {
// … 处理订单逻辑
// 发送短信通知
smsSender.send(order.getCustomerPhone(), "Your order #" + order.getId() + " has been placed!");
}
}测试类:
@SpringBootTest
public class SmsStarterTest {
@Autowired
private SmsSender smsSender;
@Test
void testSendSms() {
boolean sent = smsSender.send("+1234567890", "Hello from Spring Boot Starter!");
assertTrue(sent);
// 控制台会打印模拟发送的信息
}
}
8.5 完整可运行代码示例 由于涉及多个模块的完整代码较长,这里提供关键部分的代码框架。你需要:
这份指南涵盖了 Spring Boot Starter 的核心概念、工作原理、使用方法、自定义开发以及实战案例,力求做到详细、实用、通俗易懂且可直接运行。希望对你有所帮助!


