这是一份非常详细、实用、通俗易懂,权威、全面的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 禁用特定的自动配置类
- 3.1 在
-
创建自定义 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 完整可运行代码示例
- 6.1 添加
-
实战案例 2:集成 Spring Security Starter
- 7.1 添加
spring-boot-starter-security依赖 - 7.2 默认安全配置的行为
- 7.3 自定义用户、密码和角色 (内存、JDBC、LDAP)
- 7.4 自定义安全配置 (
@EnableWebSecurity,WebSecurityConfigurerAdapter) - 7.5 示例:配置基于表单的登录和简单授权规则
- 7.6 完整可运行代码示例 (简化版)
- 7.1 添加
-
实战案例 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 和使用项目)
- 8.1 项目结构规划 (
1. Spring Boot Starter 是什么?
1.1 核心目标:简化依赖管理和配置 Spring Boot Starter 是 Spring Boot 框架的核心组件之一,其核心目标是极大地简化基于 Spring 框架的应用开发。它主要通过以下两种方式实现:
- 简化依赖管理: 将特定功能所需的一系列相关依赖库打包成一个可传递的依赖项。开发者只需引入这一个 Starter,即可获得开发该功能所需的所有常规库。
- 简化配置: 基于"约定大于配置"的理念,提供合理的默认配置。开发者通常只需要提供少量的必要配置(如数据库连接字符串),甚至零配置,就能让功能正常工作。
1.2 传统 Spring 应用配置的痛点 在传统的 Spring 应用开发中,集成一个新的功能(如数据库访问、安全、Web MVC)通常需要:
- 查找并添加多个相关的依赖到构建文件 (
pom.xml或build.gradle),必须注意版本兼容性。 - 编写大量的 XML 配置文件或 Java 配置类 (
@Configuration),定义各种 Bean(如DataSource,EntityManagerFactory,TransactionManager,DispatcherServlet等)。 - 手动配置这些 Bean 的属性。 这个过程繁琐、容易出错,且大量重复劳动。
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类,并且你没有自己定义一个DataSourceBean,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数据库在类路径上,并且你没有配置自己的DataSourceBean,那么 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 格式。其中最重要的键是:
properties
org.springframework.boot.autoconfigure.EnableAutoConfiguration
该键的值是一个逗号分隔的、完全限定名的自动配置类列表。例如,spring-boot-autoconfigure jar 中的 spring.factories 包含大量条目:
properties
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可能只在没有用户定义的DataSourceBean 时创建。@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 通常由自动配置类注入并使用。例如:
java
@ConfigurationProperties(prefix = "spring.datasource")
public class DataSourceProperties {
private String url;
private String username;
private String password;
// ... getters and setters
}
在自动配置类中:
java
@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-*。例如:
XML
<!-- 添加 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) 可以查看更详细的报告。报告会列出:
- 评估了哪些自动配置类 (
AutoConfigurationclasses)。 - 哪些通过了条件注解 (
Condition),因此被应用 (Positive matches)。 - 哪些没有通过条件注解 (
Condition),因此没有被应用 (Negative matches)。 - 哪些因为排除等原因未被评估 (
Exclusions)。 这是理解自动配置行为的重要工具。
3.4 覆盖自动配置:自定义 Bean 和属性配置 自动配置不是不可变的。你有两种主要方式来覆盖它:
- 定义自己的 Bean: 如果你在配置类 (
@Configuration) 中定义了一个与自动配置打算创建的 Bean 类型相同的 Bean,并且该 Bean 满足条件注解(如@ConditionalOnMissingBean)的条件,那么你的 Bean 将优先被使用,自动配置的 Bean 将不会被创建。 - 使用外部配置属性: 在
application.properties或application.yml中设置属性值,这些值会通过@ConfigurationProperties绑定到自动配置使用的属性对象上,从而改变自动配置的行为。例如,设置spring.datasource.url=jdbc:mysql://localhost/mydb会覆盖默认的内存数据库配置。
3.5 禁用特定的自动配置类 如果你完全不想要某个自动配置生效,可以使用 @SpringBootApplication 或 @EnableAutoConfiguration 的 exclude 属性来禁用特定的自动配置类:
java
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class, SecurityAutoConfiguration.class})
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
或者在 application.properties 中:
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。
- 创建一个配置属性类,使用
java
@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 的文件。 文件内容如下:
properties
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 的项目中。
- 通常不包含代码或只包含极少的胶水代码。
XML
<!-- 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模块中添加依赖:XML<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文件。将这个文件包含在你的autoconfigurejar 包中。 这个 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)
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)
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。
java
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 示例代码:存储和读取数据
java
@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 应用入口:
java
@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)
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 中配置:
properties
# 配置内存用户 (实际项目用数据库或LDAP)
spring.security.user.name=admin
spring.security.user.password=admin123
spring.security.user.roles=ADMIN,USER
方法 2:自定义 UserDetailsService (更灵活) 创建一个配置类实现 UserDetailsService:
java
@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:
java
@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 或其他模板引擎):
html
<!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 完整可运行代码示例 (简化版)
java
@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: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(配置属性绑定):java@ConfigurationProperties(prefix = "sms") public class SmsProperties { private String apiKey; private String endpoint = "https://api.smsprovider.com/send"; // 默认值 // ... getters and setters } -
SmsSender.java(服务接口):javapublic interface SmsSender { boolean send(String phoneNumber, String message); } -
DefaultSmsSenderImpl.java(默认实现 - 模拟):javapublic 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(自动配置类):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:propertiesorg.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.example.sms.autoconfigure.SmsAutoConfiguration
8.3 sms-spring-boot-starter 模块开发
-
pom.xml: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) :XML<dependency> <groupId>com.example.sms</groupId> <artifactId>sms-spring-boot-starter</artifactId> <version>1.0.0</version> </dependency> -
配置参数 (
application.yml) :yamlsms: api-key: "your_real_api_key_here" # 替换成真实 key # endpoint: "https://custom.endpoint.com" # 可选,覆盖默认 -
自动注入
SmsSender并发送短信 :java@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!"); } }测试类:
java@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 完整可运行代码示例 由于涉及多个模块的完整代码较长,这里提供关键部分的代码框架。你需要:
- 创建父 Maven 项目 (可选)。
- 创建
sms-spring-boot-autoconfigure模块,包含上述SmsProperties,SmsSender,DefaultSmsSenderImpl,SmsAutoConfiguration和spring.factories。 - 创建
sms-spring-boot-starter模块,依赖autoconfigure。 - 创建一个新的 Spring Boot 应用项目 (
sms-user-demo),依赖sms-spring-boot-starter。 - 在
sms-user-demo的application.yml中配置sms.api-key。 - 在
sms-user-demo中编写一个@Service(如OrderService) 或@RestController注入SmsSender并使用它。 - 编写单元测试
SmsStarterTest注入SmsSender并测试发送。 运行sms-user-demo应用或执行测试,观察控制台输出,验证自定义 Starter 是否按预期工作。
这份指南涵盖了 Spring Boot Starter 的核心概念、工作原理、使用方法、自定义开发以及实战案例,力求做到详细、实用、通俗易懂且可直接运行。希望对你有所帮助!