Cloud Native Spring in Action
目录
设计原则
15 Factor App
数据验证和错误处理
测试
使用 Junit 5 进行单元测试
使用 @SpringBootTest 进行集成测试
使用 @WebMvcTest 测试 REST Controller
使用 @JsonTest 测试 JSON 序列化
使用 @DataJdbcTest 和 Testcontainers 测试数据持久化
使用 Reactor 和 Testcontainers 测试 Reactive 应用
使用 MockWebServer 测试 REST client
使用 @DataR2dbcTest 和 Testcontainer 测试数据持久化
使用 @WebfluxTest 测试 REST Controller
Testcontainers
数据持久化与数据管理
JDBC 审计
Flyway & Liquibase
Liquibase
安全
Spring Security & Spring Cloud API Gateway
OAuth2
JWT
OpenID Connect
KEYCLOAK
定义安全realm
OIDC 认证
CSRF
韧性
超时
重试
回退和错误处理
基于 Redis 的分布式会话管理
Kubernetes
Deployment
Service
ConfigMap & Secret
Ingress & Ingress Controller
Volumn & Persistence Volumn & Persistence Volumn Claim
Pod
Replicaset
配置管理
Kustomize
Helm
Argo & Jenkins
英文版:《Cloud Native Spring in Action》,Thomas Vitale 著
中文版:《云原生 Spring 实战》Spring Boot 与 Kubernetes 实践
设计原则
15 Factor App
“15 Factor App”是在“12 Factor App”基础上发展而来,新增的三个要素分别是:
1. API First(API 优先):强调在应用程序开发中,优先设计和定义 API。这使得应用程序的各个模块或服务之间能够通过清晰、标准的 API 进行交互通信。遵循 API First 的原则,开发团队可以更好地实现软件的解耦,提高开发效率和系统的可维护性。并且在现代云原生应用中,通过 API 可以方便地与其他微服务或外部系统进行集成,提升了应用的灵活性和可扩展性。例如,使用 API 网关来管理和规范 API 的调用,遵循最佳的 REST API 实践,定义好请求、响应 payload、API 名称、安全等方面的规范。
2. Telemetry(遥测):包括应用性能管理、特定领域的遥测数据以及健康和系统日志等方面。对应用程序的运行状态、性能指标、资源使用情况等进行实时监测和收集,能够帮助开发团队和运维人员及时了解应用的运行状况,以便在出现问题时快速定位和解决。基于这些遥测数据,平台还可以进行自动扩缩容、自我修复以及向用户和运维人员发送警报等操作。通过机器学习等技术对遥测数据进行分析,还可以为企业的未来业务策略提供参考。
3. Authentication and Authorization(认证和授权):在现代应用中,安全是至关重要的。这一要素确保只有经过认证的用户和应用程序能够访问系统资源,并根据不同的用户角色和权限进行授权。例如,采用 API token、RBAC(基于角色的访问控制)、OAuth 等认证和授权机制,对 API 的请求和响应 payload 进行加密,在网络层面设置防火墙保护,保障数据库的安全以及采用多因素认证(MFA)等措施。
这三个新增要素适应了现代云原生应用的发展需求,使得应用程序在云环境中能够更加高效、可靠、安全地运行。
12 Factor App
https://12factor.net/
- Codebase 基准代码
- Dependencies 依赖管理
- Config 配置
- Backing Services 支撑服务
- Build Release and Run 构建、发布和运行
- Processes 无状态进程
- Port Binding 端口绑定
- Concurrency 并发
- Disposability 易处理
- Dev/Prod Parity 环境对等
- Logs 日志
- Admin Processes 管理进程
数据验证和错误处理
spring-boot-starter-validation:@NotBlank、@NotNull、@Pattern、@Positive、@Valid 等。
测试
spring-boot-starter-tester:会将 JUnit 5、Mockito 和 AssertJ 的测试库导入项目。
使用 Junit 5 进行单元测试
使用 @SpringBootTest 进行集成测试
使用 @WebMvcTest 测试 REST Controller
使用 @JsonTest 测试 JSON 序列化
使用 @DataJdbcTest 和 Testcontainers 测试数据持久化
使用 Reactor 和 Testcontainers 测试 Reactive 应用
使用 MockWebServer 测试 REST client
使用 @DataR2dbcTest 和 Testcontainer 测试数据持久化
使用 @WebfluxTest 测试 REST Controller
Testcontainers
Testcontainers是一个Java库,用于在测试中方便地管理容器。
主要功能
• 容器生命周期管理:可以轻松启动和停止容器。例如,在测试数据库交互时,能快速启动一个数据库容器(如MySQL、PostgreSQL),测试完成后自动停止它。这样避免了手动安装和配置数据库,使测试环境搭建更便捷。
• 支持多种容器类型:除了常见的数据库容器,还支持消息队列容器(如RabbitMQ、Kafka)、Web容器(如Tomcat、Jetty)等。如果测试的应用依赖于这些服务,就可以用对应的容器来提供真实的测试环境。
• 与测试框架集成:很好地集成了JUnit等流行的Java测试框架。在JUnit测试类中,可以通过简单的注解和方法调用就启动和使用容器。
使用示例
1. 添加依赖:在Maven项目的pom.xml文件中添加以下依赖:
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers</artifactId>
<version>1.18.3</version>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>junit - jupiter</artifactId>
<version>1.18.3</version>
</dependency>
2. 测试数据库交互(以MySQL为例)
import org.junit.jupiter.api.Test;
import org.testcontainers.containers.MySQLContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import static org.junit.jupiter.api.Assertions.assertTrue;
@Testcontainers
public class DatabaseTest {
// 启动MySQL容器
@Container
public static MySQLContainer<?> mySQLContainer = new MySQLContainer<>("mysql:8.0")
.withDatabaseName("test_database")
.withUsername("test_user")
.withPassword("test_password");
@Test
public void testDatabaseConnection() throws SQLException {
// 获取容器的JDBC URL
String jdbcUrl = mySQLContainer.getJdbcUrl();
try (Connection connection = DriverManager.getConnection(jdbcUrl, "test_user", "test_password");
Statement statement = connection.createStatement()) {
// 执行一个简单的SQL查询
statement.execute("CREATE TABLE IF NOT EXISTS test_table (id INT, name VARCHAR(255))");
int result = statement.executeUpdate("INSERT INTO test_table (id, name) VALUES (1, 'test')");
assertTrue(result > 0);
}
}
}
在这个示例中:
• 首先定义了一个MySQLContainer,它会在测试运行时自动启动一个MySQL 8.0版本的容器,并且配置了数据库名、用户名和密码。
• 在测试方法中,通过getJdbcUrl获取容器的JDBC连接地址,然后建立连接,创建表并插入数据,最后验证插入操作是否成功。
Testcontainers极大地简化了测试环境的搭建,让测试能够在接近生产环境的容器化环境中进行,提高了测试的可靠性和有效性。
数据持久化与数据管理
JDBC 审计
使用 @EnableJdbcAuditing 启用 JDBC 审计
在配置类添加 @EnableJdbcAuditing 后,@CreatedBy,@CreatedDate,@LastModifiedBy,@LastModifiedDate 这些字段都可以加载实体字段上以捕获审计信息。
Flyway & Liquibase
Flyway和Liquibase都是管理数据库的工具,主要区别如下:
工作方式
• Flyway:基于版本号的方式管理数据库迁移。它要求开发者为每个迁移脚本按顺序编号,如V1__Create_user_table.sql、V2__Add_user_name_column.sql。在执行迁移时,Flyway会按版本号从小到大依次执行这些脚本。
• Liquibase:通过XML、YAML或SQL格式的变更日志文件来管理数据库迁移。变更日志文件描述了数据库的一系列变更,它不依赖于文件名中的版本号顺序,而是在日志文件里定义操作的顺序。
对数据库的支持
• Flyway:支持常见的数据库,如MySQL、PostgreSQL、Oracle等,但对某些数据库的特定功能支持可能有限。
• Liquibase:支持更广泛的数据库类型,包括一些比较小众的数据库,而且对不同数据库的兼容性较好,在复杂数据库环境下更有优势。
学习曲线
• Flyway:比较简单直接,容易上手,适合中小规模的项目,尤其是团队成员对数据库迁移工具不太熟悉的情况。
• Liquibase:功能强大但稍复杂,学习成本相对高些,不过它的灵活性使其适用于大型企业级项目。
集成能力
• Flyway:能很好地与构建工具(如Maven和Gradle)集成,在项目构建过程中方便地执行数据库迁移任务。
• Liquibase:除了构建工具集成外,还提供了多种接口和插件,能与不同的开发框架和部署环境集成。
Liquibase
https://docs.liquibase.com/home.html
安全
Spring Security & Spring Cloud API Gateway
OAuth2
JWT
OpenID Connect
KEYCLOAK
定义安全realm
OIDC 认证
CSRF
韧性
超时
重试
回退和错误处理
基于 Redis 的分布式会话管理
Kubernetes
Deployment
Service
ConfigMap & Secret
Ingress & Ingress Controller
Volumn & Persistence Volumn & Persistence Volumn Claim
Pod
Replicaset
配置管理
Kustomize
Helm
Argo & Jenkins
Argo和Jenkins都是用于自动化软件交付流程的工具,但它们之间有一些区别。
工作流定义方式
• Jenkins:通过传统的自由风格(Freestyle)项目或者流水线(Pipeline)来定义任务。在流水线中,使用Groovy脚本编写复杂的构建、测试和部署步骤。例如,定义一个简单的Java项目构建流水线,需要在脚本中指定代码拉取、编译、测试和打包等步骤。
• Argo:主要围绕自定义资源定义(CRD)和工作流模板(Workflow Templates)来构建工作流。它采用声明式的配置方式,通过YAML文件来定义任务之间的依赖关系和执行顺序,更符合Kubernetes原生的配置风格。
与容器生态系统的集成
• Jenkins:可以与容器集成,例如通过在构建节点上运行Docker命令来构建容器镜像,但这种集成相对来说比较手动和复杂。它本身不是为容器原生环境设计的。
• Argo:是为在Kubernetes环境中工作而构建的,与容器生态系统紧密集成。可以很自然地调度和管理容器化的工作负载,并且能够利用Kubernetes的特性,如资源管理、服务发现等。
功能重点
• Jenkins:功能丰富多样,除了构建和部署,还提供了大量的插件用于各种任务,如代码质量检查、安全扫描等。它的插件生态系统是其强大的一个方面,适合多种不同类型的软件开发流程。
• Argo:更侧重于工作流编排和容器原生应用的持续交付。特别适用于在Kubernetes集群内协调复杂的微服务部署、多阶段发布等任务,强调对容器化工作负载的高效管理。
部署和管理
• Jenkins:部署相对简单,可以通过下载WAR包在独立的服务器或者容器中运行。管理方面,需要维护Jenkins服务器本身,包括插件更新、配置备份等。
• Argo:通常部署在Kubernetes集群内,利用Kubernetes的部署和管理机制。这使得它的部署和扩展更符合云原生的方式,但也需要对Kubernetes有一定的了解才能更好地进行部署和维护。