Spring-Boot

Spring Boot 构建 Modulith 指南

本文将教你如何使用 Spring Boot 构建 Modulith,并使用 Spring Modulith 项目的特性。Modulith 是一种软件架构模式,假设将你的单体应用程序组织成逻辑模块。这些模块应尽可能独立于彼此。Modulith 平衡了单体架构和基于微服务的架构。它可以成为组织应用程序的目标模型。但你也可以将其视为从单体架构向基于微服务的方法迁移的过渡阶段。Spring Modulith 将帮助我们构建结构良好的 Spring Boot 应用程序,并验证逻辑模块之间的依赖关系。 我们将比较当前的方法和基于微服务的架构。为此,我们将实现与我最近一篇关于 使用 Spring Cloud 和 Spring Boot 3 构建微服务 的文章中所描述的非常相似的功能。 源码 你可以克隆我的 GitHub Repository,然后按照说明操作即可。 在开始之前,我们先来看看下图。它展示了我们示例系统的架构。我们有三个独立的模块,它们相互通信:employee(员工)、department(部门)和 organization(组织)。此外还有 gateway(网关)模块。它负责将内部服务作为 REST 端点暴露在应用之外。我们的模块使用 Spring Modulith 项目提供的支持向 Zipkin 实例发送追踪。 如果你想将其与先前提到的文章中描述的类似微服务架构进行比较,这是该架构的图。 让我们来看看代码的结构。默认情况下,main 的每个直接子包都被视为一个应用模块包。因此有四个应用模块:department、employee、gateway 和 organization。每个模块都包含向其他模块开放的 “provided interfaces”(提供的接口)。我们需要将它们放在应用模块根目录下。其他模块不能访问应用模块子包中的任何类或 bean。我们将在接下来的章节中详细介绍。 src/main/java └── pl └── piomin └── services ├── OrganizationAddEvent.java ├── OrganizationRemoveEvent.java ├── SpringModulith.java ├── department │ ├── DepartmentDTO.java │ ├── DepartmentExternalAPI.java │ ├── DepartmentInternalAPI.

在 Liberica 运行时容器上运行 Spring Boot 应用

1、简介 在本教程中,我们将了解如何把使用 Spring Boot 创建的 Java 应用作为 Docker 容器运行,具体来说,我们将在 Alpaquita Linux 上使用 Liberica JDK 来创建运行我们应用的 Docker 镜像。 Liberica JDK 和 Alpaquita Linux 是 BellSoft 产品的一部分。BellSoft 的愿景是使 Java 成为云原生应用程序的首选语言。 2、简单的 Spring Boot 应用 先用 Java 创建一个简单的应用,然后将其容器化。通过 Spring Boot,我们只需进行最少的配置,就能轻松创建基于 Spring 的独立生产级应用。 初始化 Spring Boot 应用的最简单方法是使用 Spring Boot CLI。通过它,可以在命令行中使用 start.springboot.io 创建一个新项目: $ spring init --build=gradle --dependencies=web spring-bellsoft 如上,添加了 web 依赖,以构建 RESTful API,并将 Apache Tomcat 作为默认的嵌入式容器。选择 Gradle 作为构建工具,默认的语言是 Java。 然后,可以将生成的项目导入 IDE(如 IntelliJ Idea),开始开发应用。 添加一个简单的 REST API,接收一个 Integer 参数,并返回等于或小于该数字的斐波纳契数列:

在 Spring Boot Properties/Yaml 文件中使用环境变量

1、概览 本文介绍了如何在 Spring Boot 的 application.properties 和 application.yml 中使用环境变量,以及如何在代码中使用这些属性。 2、在 application.properties 文件中使用环境变量 定义一个名为 JAVA_HOME 的全局环境变量,其值为 C:\Program Files\Java\jdk-11.0.14。 要在 Spring Boot 的 application.properties 中使用该变量,需要用大括号将其包裹起来: java.home=${JAVA_HOME} 也可以以同样的方式使用系统属性(System Properties)。例如,在 Windows 系统中,默认情况下会定义操作系统属性: environment.name=${OS} 还可以组合多个变量值。定义另一个环境变量 HELLO_BAELDUNG,其值为 Hello Baeldung。现在可以将两个变量连接起来: baeldung.presentation=${HELLO_BAELDUNG}. Java is installed in the folder: ${JAVA_HOME} baeldung.presentation 属性值现在为:Hello Baeldung. Java is installed in the folder: C:\Program Files\Java\jdk-11.0.14. 3、在代码中使用特定环境属性 启动 Spring Context 后,就可以在代码中注入属性值。 3.1、使用 @Value 注入属性值 可以使用 @Value 注解在 setter 方法、构造器和字段上进行注入: @Value("${baeldung.presentation}") private String baeldungPresentation; 3.2、从 Spring Environment 获取值 还可以通过 Spring 的 Environment 获取属性值。

Spring Boot 3 和 Spring Framework 6.0 - 新功能

1、概览 本文简单地介绍了 Spring Boot 3 和 Spring Framework 6.0 中的新特性。 2、Java 17 之前已经支持Java 17,现在这个 LTS 版本成为基线版本。 由于 Java 本身不是本文的主题,这里只会列举对 Spring Boot 开发人员最重要的新特性。 2.1、Record Java Record(JEP 395),是一种快速创建数据类(Data Class)方式,即那些目的仅仅是包含数据并在模块之间传递数据的类,也被称为 POJO(Plain Old Java Objects,简单Java对象)和 DTO(Data Transfer Objects,数据传输对象)。 使用 Record 可以轻松创建不可变的 DTO: public record Person (String name, String address) {} 目前,在将它们与 Bean Validation 结合使用时,需要小心,因为构造函数参数不支持验证约束,例如在 Controller 方法中的 JSON 对象。 2.2、字符块 通过 JEP 378,现在就可以创建多行文本块,而无需在换行时连接字符串: String textBlock = """ Hello, this is a multi-line text block. """; 2.

Spring Boot 整合 Redisson

Redisson 是一个功能十分强大的 Redis Java 客户端,它提供了丰富的功能和API,支持同步和异步操作,以及 RxJava 和响应式编程模型。Redisson 提供了50多个基于 Redis 的 Java 对象和服务,包括 分布式锁、原子计数器、分布式集合(Set、Map、List、Queue) 等高级功能。它还还支持本地缓存和 RPC 调用等功能,是开发分布式应用和使用 Redis 的理想选择。 总之,Redisson 所提供的功能已经远远超出了一个 Redis 客户端的范畴,Redis 官方也 推荐使用它 作为 Java 的 Redis 客户端。 之前我们介绍过 如何在 Spring Boot 中整合、使用 Redis。我们用到了 Spring Data Redis 组件,这是由 Spring 提供的抽象,可以使用 Jedis、Lettuce 等客户端作为实现。 Redisson 官方提供了一个 redisson-spring-boot-starter 组件,它正是 Spring Data Redis 抽象的实现,也就是说,我们可以直接使用 redisson-spring-boot-starter 无缝替换 spring-boot-starter-data-redis。 本文将会带你了解如何在 Spring Boot 中通过 redisson-spring-boot-starter 整合、使用 Redisson。 整合 Redisson 添加依赖 添加 redisson-spring-boot-starter 依赖即可。 <!-- https://mvnrepository.com/artifact/org.redisson/redisson-spring-boot-starter --> <dependency> <groupId>org.

在 Spring Boot 中整合、使用 Redis

Redis 是一款开源的,使用 C 开发的高性能内存 Key/Value 数据库,支持 String、Set、Hash、List、Stream 等等数据类型。它被广泛用于缓存、消息队列、实时分析、计数器和排行榜等场景。基本上是当代应用中必不可少的软件! Spring Boot 对 Redis 提供了开箱即用的组件:spring-boot-starter-data-redis。通过这个 starter,我们只需要几行简单的配置就可以快速地在 Spring Boot 中整合、使用 Redis。 Spring Boot 整合 Redis Maven 依赖 <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> 除了 spring-boot-starter-data-redis 外,还添加了 commons-pool2 依赖,是因为我们需要使用到连接池。 配置属性 只需要在 application.yaml | properties 中配置如下常用的基本属性即可: spring: data: redis: # 连接地址 host: "localhost" # 端口 port: 6379 # 数据库 database: 0 # 用户名,如果有 # username: # 密码,如果有 # password: # 连接超时 connect-timeout: 5s # 读超时 timeout: 5s # Lettuce 客户端的配置 lettuce: # 连接池配置 pool: # 最小空闲连接 min-idle: 0 # 最大空闲连接 max-idle: 8 # 最大活跃连接 max-active: 8 # 从连接池获取连接 最大超时时间,小于等于0则表示不会超时 max-wait: -1ms 注意,如果你使用的是 spring boot 2.

在 Spring Boot 中使用 AOP 和 SpEL 记录操作日志

通常,我们在 Spring Boot 应用中都是用过 AOP 和自定义注解的方式来记录请求日志、操作日志等。 这种方式记录到的日志数据,都是固定的模板数据。如:XXX 删除了用户、XXX 新增了用户、XXX 查询了用户列表 等等。 如果我们想要在日志内容中添加更多的业务信息,如:XXX 删除了用户 ID = xxx 的记录,那么可以通过使用 AOP 和 SpEL 表达式来实现。 SpEL 表达式简介 SpEL(Spring Expression Language) 是 Spring 中的表达式语言,用于在运行时评估和处理表达式。它提供了一种灵活的方式来访问和操作对象的属性、方法和其他表达式。SpEL可以用于配置文件、注解、XML 配置等多种场景,用于实现动态的、可配置的行为。它支持常见的表达式操作,如算术运算、逻辑运算、条件判断、集合操作等,并且可以与 Spring 框架的其他功能整合使用。 通俗理解就是,可以在 Spring 应用中使用 String 定义表达式,在表达式中可以创建、定义对象。以及访问对象的属性、方法,进行逻辑运算等等。最后得到表达式的输出结果! 一个简单的例子如下: import org.springframework.expression.Expression; import org.springframework.expression.ExpressionParser; import org.springframework.expression.EvaluationContext; import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.expression.spel.support.StandardEvaluationContext; public class Main { public static void main(String[] args) { // 执行上下文 EvaluationContext context = new StandardEvaluationContext(); context.setVariable("param", "World"); // 设置参数到上下文 // 解析器 ExpressionParser parser = new SpelExpressionParser(); // 使用解析器,解析 SpEL 表达式 // 该表达式中定义了字符串 'Hello ' 常量,并且调用它的 .

Spring Boot 接收数组参数

普通的数组 定义一个简单的 Controller,它接收一个 String[] 类型的数组参数,如下: @RestController @RequestMapping("/demo") public class DemoController { @GetMapping public Object demo (@RequestParam("hobby") String[] hobby) { return hobby; } } Spring Boot 可以直接把以逗号分割的参数封装为集合、数组,例如: $ curl "localhost:8080/demo?hobby=chang,tiao,rap" ["chang","tiao","rap"] 其他框架、程序不一定会根据逗号进行分割。更优雅的方式,也是通用的方式应该是多次声明同名参数,例如: $ curl "localhost:8080/demo?hobby=chang&hobby=tiao&hobby=rap" ["chang","tiao","rap"] 数组也可以替换为 Collection 接口,Spring 都会正确地处理。特别是在一些需要对数组参数去重的场景,推荐使用 Set 作为参数,如下: @GetMapping public Object demo (@RequestParam("hobby") Set<String> hobby) { return hobby; } 发起请求,这一次 rap 值重复传递了 3 次: $ "localhost:8080/demo?hobby=chang&hobby=tiao&hobby=rap&hobby=rap&hobby=rap" ["chang","tiao","rap"] 得益于 Set 自带去重的特性,所以最终 hobby 集合中重复的 rap 值,只保留了一个。 使用 Set 作为参数的时候,默认使用的实现是 java.

JdbcTemplate 中废弃的 query(...) 和 queryForObject(...) 方法

1、概览 在 Spring Boot 2.4.x 以后,JdbcTemplate 中有几个方法注解了 @Deprecated,也就是说被废弃了: query(String sql, @Nullable Object[] args, ResultSetExtractor<T> rse) query(String sql, @Nullable Object[] args, RowCallbackHandler rch) query(String sql, @Nullable Object[] args, RowMapper<T> rowMapper) queryForObject(String sql, @Nullable Object[] args, RowMapper<T> rowMapper); queryForObject(String sql, @Nullable Object[] args, Class<T> requiredType) queryForList(String sql, @Nullable Object[] args, Class<T> elementType) 这些过时的方法都使用对象数组 Object[] args 传递参数。 JdbcTemplate 又提供了一些新的方法来代替它们,新方法使用了 “可变参数”,即 Varargs 传递参数。 本文接下来会讲解一下新旧方法的用法和区别。 2、数据库 使用 H2 内存数据库进行演示,假如我们有一张 student 表,如下: CREATE TABLE student ( student_id INT AUTO_INCREMENT PRIMARY KEY, student_name VARCHAR(255) NOT NULL, age INT, grade INT NOT NULL, gender VARCHAR(10) NOT NULL, state VARCHAR(100) NOT NULL ); -- Student 1 INSERT INTO student (student_name, age, grade, gender, state) VALUES ('John Smith', 18, 3, 'Male', 'California'); -- Student 2 INSERT INTO student (student_name, age, grade, gender, state) VALUES ('Emily Johnson', 17, 2, 'Female', 'New York'); -- 其他 insert 语句 .

Spring Boot v3.1.4 发布

⭐ 新特性 在 JavaVersion 枚举中添加 TWENTY_ONE #37364 🐞 Bug 修复 当 SLF4J 和 Logback 在多线程中并行初始化时,由于 SubstituteLoggerFactory 被认为是一个竞争的 LoggerFactory 实现,启动可能会失败 #37484 使用 metadata-url 时,Saml2RelyingPartyAutoConfiguration 会忽略 sign-request #37482 在 DomainSocket 工具中泄漏文件描述符/套接字 #37460 在 WelcomePageHandlerMapping 中,无效的 Accept 头会产生 HTTP 500 #37457 PrivateKeyParser 不支持 ed448、XDH 和 RSA-PSS 密钥 #37422 使用 Gradle 8.3 并配置 Java 工具链语言版本时,“languageVersion is final and cannot be changed” #37380 当 @ConfigurationProperties 注解的记录有多个构造函数时,AOT 处理失败 #37336 使用 Gradle 和 dependency management 插件时,Spring Boot dependency management 对 ehcache 无效 #37270 SslStoreBundle 实现不是不可变的 #37222 解析因使用大写字母而无效的 OCI image 名称的速度非常慢 #37183 生成和消费不同的跟踪传播格式不起作用 #37178 使用除 secp384r1 之外的椭圆曲线时,使用 https 失败 #37169 在 3.