Spring

Spring 中的 @ConditionalOnProperty 注解

1、概览 本文将带你了解 Spring 中 @ConditionalOnProperty 注解的作用和用法。 2、@ConditionalOnProperty 的作用 通常,在开发基于 Spring 的应用时,需要根据配置属性是否存在,或者配置属性有指定的值来有条件地创建一些 Bean。 例如,我们需要注册一个 DataSource Bean,并且要根据属性值设置为 prod 还是 test 来创建生产数据库或测试数据库。 这正是 @ConditionalOnProperty 注解的用武之地。 简而言之,@ConditionalOnProperty 只有在环境属性存在且具有指定值的情况下才会启用 Bean 注册。默认情况下,指定的属性必须已定义且等于指定的值。 熟悉了 @ConditionalOnProperty 注解的用途后,接着来深入了解一下如何使用。 3、@ConditionalOnProperty 注解实践 开发一个基本的电子邮件通知系统来示范 @ConditionalOnProperty 的使用。 首先,创建一个简单的服务来发送通知消息。 定义 NotificationSender 接口: public interface NotificationSender { String send(String message); } 接下来,提供一个 NotificationSender 接口的实现来发送电子邮件: public class EmailNotification implements NotificationSender { @Override public String send(String message) { return "Email Notification: " + message; } } 现在,来看看如何使用 @ConditionalOnProperty 注解。

Spring 中的 @DynamicPropertySource 注解

1、概览 当代应用通常需要连接到各种外部服务,如 PostgreSQL、Apache Kafka、Cassandra、Redis 和其他外部 API。 本文将带你了解 Spring 如何通过引入动态属性(@DynamicPropertySource)来帮助测试此类应用。 2、问题:动态属性 假设我们正在开发一个使用 PostgreSQL 作为数据库的应用。 创建 JPA 实体: @Entity @Table(name = "articles") public class Article { @Id @GeneratedValue(strategy = IDENTITY) private Long id; private String title; private String content; // get、set 省略 } 我们需要编写测试来确保应用按预期运行,由于该测试需要与真实数据库创建连接,我们应该事先建立一个 PostgreSQL 实例。 在测试执行过程中,有不同的方法来设置此类基础工具。事实上,这类解决方案主要有三类: 专门为测试设置一个单独的数据库服务器 使用一些轻量级的、测试专用的替代品,如 H2 让测试本身管理数据库的生命周期 由于未区分测试环境和生产环境,与使用 H2 等测试替身相比,有更好的选择。第三个选项不仅可以与真实数据库一起使用,还可以为测试提供更好的隔离性。此外,借助 Docker 和 Testcontainers 等技术,实现第三个选项非常容易。 如果使用 Testcontainers 等技术,测试流程如下: 在所有测试前设置 PostgreSQL 等组件。通常,这些组件会监听随机端口。 运行测试。 卸载组件。 如果 PostgreSQL 容器每次都监听随机端口,那么我们就应该以某种方式动态设置和更改 spring.datasource.url 配置属性。基本上,每个测试都应该有自己的配置属性版本。 当配置是静态的时候,可以使用 Spring Boot 的配置管理工具轻松地对其进行管理。但是,当我们面对的是动态配置时,同样的任务就会变得比较麻烦。

Spring 中的事件(Event)机制

1、Spring 事件机制 有的人可能会觉得 Spring 中的事件机制很神奇,一个地方发消息,另一个地方收消息,跟 MQ 一样。其实,Spring 中的事件本质上就是观察者模式的应用。事件有其便利的一面,但是用多了也容易导致混乱,所以在实际项目中,我们还是要谨慎选择是否使用 Spring 事件。 2、简单实践 先用一个简单的案例,来让大家了解一下 Spring 中事件的应用。 事件发布流程中,有三个核心概念,它们之间的关系如下图: 事件源(ApplicationEvent):这个就是你要发布的事件对象。 事件发布器(ApplicationEventPublisher):这是事件的发布工具。 事件监听器(ApplicationListener):这个相当于是事件的消费者。 以上三个要素,事件源和事件监听器都可以有多个,事件发布器(通常是由容器来扮演)一般来说只有一个。 接下来,让我们通过一个简单的案例来演示一下 Spring 中事件的用法。 首先,我们需要自定义一个事件对象,自定义的事件继承自 ApplicationEvent 类,如下: public class MyEvent extends ApplicationEvent { private String name; public MyEvent(Object source, String name) { super(source); this.name = name; } @Override public String toString() { return "MyEvent{" + "name='" + name + '\'' + "} " + super.toString(); } } 这里只额外定义了一个 name 属性,如果大家在事件发送的时候需要传递的数据比较多,那么就可以在这里定义更多的属性。 在具体实践中,事件源并非一定要继承自 ApplicationEvent,事件源也可以是一个普通的 Java 类,如果是普通的 Java 类,系统会自动将之封装为一个 PayloadApplicationEvent 对象去发送。

Spring 中 @Valid 和 @Validated 注解的区别

1、概览 本文将带你了解 Spring 中 @Valid 和 @Validated 注解的用法和它们之间的区别。 在大多数应用中,验证用户输入是常见的功能。在 Java 生态系统中,一般使用 Java Standard Bean Validation API 来支持这一点,从 Spring 4.0 版本开始,它就与 Spring 完美集成。@Valid 和 @Validated 注解就源自于这个 Standard Bean API。 2、@Valid 和 @Validated 注解 在 Spring 中,通常使用 JSR-303 的 @Valid 注解进行方法级验证,以及用于标记成员属性以进行验证。不过,该注解不支持分组验证。 分组(Group)可以帮助限制在验证过程中应用的约束条件。一个特定的使用案例是 UI 引导(UI wizards)。在第一步中,可能会有一组特定的字段。在后续步骤中,可能还有同一个 Bean 的另一组字段。因此,需要在每个步骤中对这些有限的字段应用约束条件,但是 @Valid 无法支持这样的功能。 对于分组级(Group-Level)验证,必须使用 Spring 的 @Validated,它是 JSR-303 的 @Valid 的变体,用于方法级。对于成员属性的标记,继续使用 @Valid 注解就行。 3、示例 使用 Spring Boot 开发一个简单的用户注册表单。 首先,只有 name 和 password 属性: public class UserAccount { @NotNull @Size(min = 4, max = 15) private String password; @NotBlank private String name; // 构造函数、Get、Set 省略 } 接下来是 Controller。在 saveBasicInfo 方法参数上使用 @Valid 注解来验证用户输入:

Spring MVC 处理 JSON 参数

1、概览 本文将带你了解如何在 Spring MVC 中处理 POST 和 GET 请求中发送 JSON 参数。 2、Spring MVC 中的 JSON 参数 使用 JSON 发送或接收数据是 Web 开发人员的常见做法。JSON 字符串的分层结构为 HTTP 请求参数提供了一种更紧凑、更易于人类阅读的表示方式。 默认情况下,Spring MVC 通过了一系列内置的底层 Property Editor 为 String 等简单数据类型提供开箱即用的数据绑定。 但是,在实际项目中,可能需要绑定更复杂的数据类型。例如:将 JSON 参数映射到 Model Object。 3、使用 POST 请求发送 JSON Spring 提供了一种简单的方式来处理 POST 请求发送 JSON 数据。内置的 @RequestBody 注解可以自动将请求体中的 JSON 数据反序列化为特定的 Model 对象。 通常情况下,无需自己解析请求体,Spring MVC 会使用 Jackson 库来完成所有的工作。 首先,创建一个 Model 对象来表示传递的 JSON 数据。例如 Product 类: public class Product { private int id; private String name; private double price; // 构造函数、get、set 方法省略 } 其次,定义一个接受 POST 请求的 Spring Handler 方法:

以 String 形式读取 HTTP 响应体

1、简介 本文介绍了以字符串形式读取 HTTP 响应体的几种方式。 2、HttpClient Java 11 中添加了 HttpClient,用于访问 Web 资源。与 HttpURLConnection 不同的是,HttpClient 除了支持 HTTP/1.1 和 HTTP/2 外,它还提供同步和异步请求类型。 HttpClient 提供了一个现代化的 API,具有很大的灵活性和强大的功能。该 API 由三个核心类组成:HttpClient、HttpRequest 和 HttpResponse。 HttpResponse 描述了 HttpRequest 调用的结果。HttpResponse 并非直接创建,而是在完全接收到正文(Body)后才可用。 首先创建 HttpClient 和 HttpRequest 对象: HttpClient client = HttpClient.newHttpClient(); HttpRequest request = HttpRequest.newBuilder() .uri(URI.create(DUMMY_URL)) .build(); 然后,使用 BodyHandlers 并调用 ofString() 方法返回 String 响应: HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); 3、HttpURLConnection HttpURLConnection 是一个轻量级 HTTP 客户端,用于通过 HTTP 或 HTTPS 协议访问资源,它允许创建一个 InputStream。获得 InputStream 后,就可以像读取普通本地文件一样读取它。 在 Java 中,可以用来访问互联网的主要类是 java.

检测 Spring 事务是否处于活动状态

1、概览 本文将带你了解在代码中检测 Spring 事务的几种方法。 2、事务配置 要在 Spring 中运行事务,必须启用事务管理。如果使用的是Spring Boot 项目,并且依赖了 spring-data- 或 spring-tx,Spring 会默认启用事务管理。否则,必须手动启用事务并明确提供事务管理器(Transaction Manager)。 首先,需要在 @Configuration 类中添加 @EnableTransactionManagement 注解。这样,在项目中就可以使用 Spring 注解驱动的事务管理了。 接下来,必须提供 PlatformTransactionManager 或 ReactiveTransactionManager Bean。该 Bean 需要一个数据源。可以选择使用一些常用库,如 H2 或 MySQL 库。这不是本文的重点。 启用事务后,就可以使用 @Transactional 注解来开启事务。 3、TransactionSynchronizationManager Spring 提供了一个名为 TransactionSychronizationManager 的类。该类有一个名为 isActualTransactionActive() 的静态方法可以让我们知道自己是否处于事务。 测试如下,用 @Transactional 注解一个测试方法。在方法中断言 isActualTransactionActive() 返回 true: @Test @Transactional public void givenTransactional_whenCheckingForActiveTransaction_thenReceiveTrue() { assertTrue(TransactionSynchronizationManager.isActualTransactionActive()); } 同样,删除 @Transactional 注解时,测试应断言返回 false: @Test public void givenNoTransactional_whenCheckingForActiveTransaction_thenReceiveFalse() { assertFalse(TransactionSynchronizationManager.isActualTransactionActive()); } 4、Spring 事务日志 也许你并不需要以编程式的方式来检测事务,可能只是想在应用的日志中查看事务发生的时间,可以在 properties 文件中启用 Spring 的事务日志:

Spring 加载时织入(Load-Time Weaving)

简介 本文将带你了解 Spring 加载时织入(Load-Time Weaving)是如何工作的,以便在运行时应用 Hibernate 字节码增强机制。 一般来说,字节码增强机制是在使用 Maven 或 Gradle 插件构建项目时应用的。 Domain Model 假设有以下 Attachment 实体,如下: @Entity @Table(name = "attachment") public class Attachment { @Id private Long id; private String name; @Enumerated @Column(name = "media_type") private MediaType mediaType; @Lob @Column(columnDefinition="BLOB") @Basic(fetch = FetchType.LAZY) private byte[] content; // get、set 和其他方法省略 } content 属性使用的是 FetchType.LAZY 抓取策略,但在 POJO 实体上无法懒加载实体属性,因此需要 Hibernate 字节码增强机制来实现这一目标。 Hibernate 字节码增强机制 Hibernate 字节码增强机制允许我们更改 JPA 实体的字节码,这样就可以拦截 getter 和 setter 方法调用,从而达到以下目的 懒加载属性 记录实体的修改 如上所述,字节码增强机制是通过 Maven 或 Gradle 插件配置的,该插件会在项目构建时增强实体类。

CDS(Class Data Sharing)在 Spring 6.1 中的应用

正如 官方文档 所述,类数据共享(CDS)通过将类元数据缓存在 Archive(归档/存档) 文件中,使其可以快速预加载到新启动的 JVM 中,从而帮助缩短 JVM 的启动时间和内存占用。这加快了类加载速度,而类加载速度是启动时间的一个重要因素。大多数最新的 JDK 发行版中预先打包了默认的 CDS 归档,其中包含了常见 JDK 类的元数据。你也可以创建自定义的 CDS 归档,以加快类在自己应用中的加载速度。 GraalVM 原生镜像 和 Project CRaC 都能让 Spring Boot 应用在几十毫秒内启动。那么,为什么要关注 CDS 呢? 主要有三个原因: 它是 OpenJDK 主线中成熟且可用于生产的技术,与 GraalVM 和 Project CRaC 相比,它更易于使用,因为它具有较少的限制和副作用。 正如 Brian Goetz 在他在 Devoxx 上的 Project Leyden 演讲 中提到的:“大多数人今天不使用 CDS,但可能应该使用,因为他们可以通过相对较少的工作获得合理的启动性能提升。” 在每一个新的 JVM 版本中,这项技术都会变得越来越好,Project Leyden 的目标是在不久的将来增加更多的优势。 接下来,让我们一起探究 CDS 能为你的 Spring 应用带来什么? 在 Spring 6.1 中引入 CDS 初始支持 Spring 6.1 带来了一个新的 “类数据共享” 文档章节,解释了优化应用的两个步骤: 使用新增的 -Dspring.

Spring MVC 教程

1、概览 这是一个简单的 Spring MVC 教程,介绍如何通过基于 Java 的配置和 XML 配置来建立 Spring MVC 项目。 Spring MVC 依赖: <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>${org.springframework.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${org.springframework.version}</version> </dependency> 2、Spring MVC 是啥? 顾名思义,它是 Spring 框架中处理模型(Model)- 视图(View)- 控制器(Controller)或 MVC 模式的一个模块。它结合了 MVC 模式的所有优点和 Spring 的便利性。 Spring 使用其 DispatcherServlet 前控制器模式实现 MVC。 简而言之,DispatcherServlet 是将请求路由到预定目的地的主要控制器。Model 只是应用的数据,而视图则由各种模板引擎来表示。 3、使用 Java 配置的 Spring MVC 要通过 Java 配置类启用 Spring MVC 支持,只需添加 @EnableWebMvc 注解即可: @EnableWebMvc @Configuration public class WebConfig { /// ... } 这将设置 MVC 项目所需的基本支持,如注册处理器、映射器、类型转换器、验证支持、消息转换器和异常处理。