1、概览 空指针异常 NullPointerException 是一个常见问题,避免这种问题的方法之一是在方法参数上添加 @NotNull 等校验注解。
给方法参数添加了 @NotNull 注解后,还需要其他的一些设置才能自动对参数进行非空校验。
2、给方法参数添加 @NotNull 注解 创建一个类,其中包含一个返回 String 长度的方法。
在 String 参数上添加 @NotNull 注解:
public class NotNullMethodParameter { public int validateNotNull(@NotNull String data) { return data.length(); } } 注意,有多个包下都有 @NotNull 注解,我们使用的应该是 jakarta.validation.constraints 包。
创建 NotNullMethodParameter 实例,然后使用 null 参数调用方法。
NotNullMethodParameter notNullMethodParameter = new NotNullMethodParameter(); notNullMethodParameter.doesNotValidate(null); 尽管在参数上使用了 @NotNull,但还是出现了空指针异常:NullPointerException。
注解未生效,因为没有 Validator 来执行它。
3、添加 Validator 添加 Hibernate Validator(jakarta.validation 的实现)来识别 @NotNull。
<dependency> <groupId>org.hibernate.validator</groupId> <artifactId>hibernate-validator</artifactId> <version>8.0.0.Final</version> </dependency> 使用默认的 ValidatorFactory 创建 validator。
1、概览 本文将会带你了解在 Java 响应式编程中如何将 Flux<DataBuffer> 读取到 InputStream。
2、请求设置 首先,使用 Spring Reactive WebClient 发起 GET 请求。使用由 gorest.co.in 托管的公共 API 端点来进行测试:
String REQUEST_ENDPOINT = "https://gorest.co.in/public/v2/users"; 接下来,定义 getWebClient() 方法,用于获取 WebClient 类的新实例:
static WebClient getWebClient() { WebClient.Builder webClientBuilder = WebClient.builder(); return webClientBuilder.build(); } 至此,我们就可以向 /public/v2/users 端点发出 GET 请求了。注意,必须以 Flux<DataBuffer> 对象的形式获取响应体。
3、BodyExtractors 和 DataBufferUtils 我们可以使用 spring-webflux 中 BodyExtractors 类的 toDataBuffers() 方法将响应体提取到 Flux<DataBuffer> 中。
将 body 构建为 Flux<DataBuffer> 类型的实例:
Flux<DataBuffer> body = client .get( .uri(REQUEST_ENDPOINT) .exchangeToFlux( clientResponse -> { return clientResponse.
当我们想在 Spring 容器启动或者关闭的时候,做一些初始化操作或者对象销毁操作,我们可以怎么做?
注意我这里说的是容器启动或者关闭的时候,不是某一个 Bean 初始化或者销毁的时候!
1、Lifecycle 对于上面提到的问题,如果你稍微研究过 Spring,应该是了解其里边有一个 Lifecycle 接口,通过这个接口,我们可以在 Spring 容器启动或者关闭的时候,做一些自己需要的事情。
我们先来看下 Lifecycle 接口:
public interface Lifecycle { void start(); void stop(); boolean isRunning(); } 这个接口一共就三个方法:
start:启动组件,该方法在执行之前,先调用 isRunning 方法判断组件是否已经启动了,如果已经启动了,就不重复启动了。 stop:停止组件,该方法在执行之前,先调用 isRunning 方法判断组件是否已经停止运行了,如果已经停止运行了,就不再重复停止了。 isRunning:这个是返回组件是否已经处于运行状态了,对于容器来说,只有当容器中的所有适用组件都处于运行状态时,这个方法返回 true,否则返回 false。 如果我们想自定义一个 Lifecycle,方式如下:
@Component public class MyLifeCycle implements Lifecycle { private volatile boolean running; @Override public void start() { running = true; System.out.println("start"); } @Override public void stop() { running = false; System.out.println("stop"); } @Override public boolean isRunning() { return running; } } 需要自定义一个 running 变量,该变量用来描述当前组件是否处于运行/停止状态,因为系统在调用 start 和 stop 方法的时候,都会先调用 isRunning 方法,用以确认是否需要真的调用 start/stop 方法。
1、概览 在本文中,我们将创建一个简单的 Spring 应用,用于连接到 ActiveMQ 并发送和接收消息。我们将重点关注测试这个应用以及测试 Spring JMS 的不同方法。
Spring JMS 是 Spring 框架提供的一个模块,用于支持与 Java 消息服务(Java Message Service,JMS)提供者的集成。JMS是一种用于在分布式系统中发送、接收和传递消息的标准 API。
2、应用设置 首先,创建一个用于测试的基本 Spring 应用。添加必要的依赖,并实现消息处理。
2.1、依赖 在 pom.xml 中添加所需的依赖。我们需要 Spring JMS 来监听 JMS 消息。我们将在部分测试中使用 ActiveMQ-Junit 启动嵌入式 ActiveMQ 实例,并在其他测试中使用 TestContainers 运行 ActiveMQ Docker 容器:
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-jms</artifactId> <version>4.3.4.RELEASE</version> </dependency> <dependency> <groupId>org.apache.activemq.tooling</groupId> <artifactId>activemq-junit</artifactId> <version>5.16.5</version> <scope>test</scope> </dependency> <dependency> <groupId>org.testcontainers</groupId> <artifactId>testcontainers</artifactId> <version>1.17.3</version> <scope>test</scope> </dependency> 2.2、应用代码 现在,创建一个可以监听消息的 Spring 应用:
@ComponentScan public class JmsApplication { public static void main(String[] args) { ApplicationContext context = new AnnotationConfigApplicationContext(JmsApplication.
1、简介 本文将带你了解 @Spy 和 @SpyBean 之间的区别和用法。
2、基本应用 本文中,我们使用一个简单的订单应用,其中包括一个用于创建订单的订单服务,以及一个用于在处理订单时发出通知的通知服务。
OrderService 有一个 save() 方法,用于接收 Order 对象,使用 OrderRepository 保存该对象,并调用 NotificationService:
@Service public class OrderService { public final OrderRepository orderRepository; public final NotificationService notificationService; public OrderService(OrderRepository orderRepository, NotificationService notificationService) { this.orderRepository = orderRepository; this.notificationService = notificationService; } public Order save(Order order) { order = orderRepository.save(order); notificationService.notify(order); if(!notificationService.raiseAlert(order)){ throw new RuntimeException("Alert not raised"); } return order; } } 为简单起见,我们假设 notify() 方法仅在日志中输出订单信息。实际上,它可能涉及更复杂的操作,例如通过队列向下游应用发送电子邮件或消息。
我们还假设,每个创建的订单都必须通过调用 ExternalAlertService 来接收警报(Alert),如果警报成功,则返回 true,如果 OrderService 没有发出警报,则会失败:
1、概览 本文将带你了解如何在 Spring 6 中使用 RSocket。
随着 Spring 6 引入声明式 RSocket 客户端,使用 RSocket 变得更加简单。这一功能消除了重复的模板代码,使开发人员能够更高效地使用 RSocket。
2、Maven 依赖 首先,创建 Spring Boot 项目,并在 pom.xml 文件中添加 spring-boot-starter-rsocket 依赖:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-rsocket</artifactId> <version>3.1.4</version> </dependency> 3、创建 RSocket Server 首先,创建一个 responder(应答器),通过 Controller 来管理传入的请求:
@MessageMapping("MyDestination") public Mono<String> message(Mono<String> input) { return input.doOnNext(msg -> System.out.println("Request is:" + msg + ",Request!")) .map(msg -> msg + ",Response!"); } 接着,在 application.properties 文件中添加以下属性,以在 7000 端口启动服务( MyDestination):
spring.rsocket.server.port=7000 4、客户端 现在,开发客户端。为了简单起见,我们在同一个项目中创建客户端,但将其放在一个单独的包中。实际开发中,它们应该放在一个单独的项目中。
创建客户端接口:
public interface MessageClient { @RSocketExchange("MyDestination") Mono<String> sendMessage(Mono<String> input); } 在使用客户端接口时,通过 @RSocketExchange 来指定 RSocket 端点。基本上,这意味着我们需要一些信息来建立端点路径。可以在接口级别上通过分配一个共享路径来实现。这非常简单,帮助我们知道要使用哪个端点。
1、概览 无论是单元测试还是集成测试,测试对于任何应用程序都至关重要。SpringRunner 和 SpringBootTest 类是运行集成测试的基础。
在本教程中,我们将了解 SpringRunner 和 @SpringBootTest 的用法,以及它们之间的区别。
2、SpringRunner SpringRunner 是 SpringJUnit4ClassRunner 类的别名,可用于基于 JUnit4 的测试类。它加载 Spring TestContext,通过 Spring TestContext,Spring Bean 和 Configuration 可与 JUnit 注解一起使用。需要 JUnit 4.12 或更高版本才能使用它。
通过 @RunWith(SpringRunner.class) 注解测试类来使用此功能:
@RunWith(SpringRunner.class) public class SampleIntegrationTest { @Test public void test() { // } } 3、SpringBootTest SpringBootTest 是 SpringRunner 的替代品,可与 JUnit5 配合使用。它还用于运行集成测试和加载 Spring TestContext。
它的功能非常丰富,可通过注解参数提供多种配置。它支持各种 Web 环境模式,如 MOCK、RANDOM_PORT、DEFINED_PORT 和 NONE。我们可以通过注解传递 application properties,在测试运行之前将其注入到 Spring Environment 中。
@SpringBootTest( properties = {"user.name=test_user"}, webEnvironment = MOCK) public class SampleIntegrationTest { @Test public void test() { // } } 要运行集成测试,必须在类级别添加注解 @SpringBootTest。
scope 属性,相信大家都知道,一共有六种:
取值 含义 生效条件 singleton 表示这个 Bean 是单例的,在 Spring 容器中,只会存在一个实例。 prototype 多例模式,每次从 Spring 容器中获取 Bean 的时候,才会创建 Bean 的实例出来。 request 当有一个新的请求到达的时候,会创建一个 Bean 的实例处理。 web 环境下生效 session 当有一个新的会话的时候,会创建一个 Bean 的实例出来。 web 环境下生效 application 这个表示在项目的整个生命周期中,只有一个 Bean。 web 环境下生效 gloablsession 有点类似于 application,但是这个是在 portlet 环境下使用的。 web 环境下生效 这个用法也很简单,通过配置就可以设置一个 Bean 是否为单例模式。
1、问题呈现 今天我要说的不是基础用法,是另外一个问题,假设我现在有如下两个 Bean:
@Service public class UserService { @Autowired UserDao userDao; } @Repository public class UserDao { } 在 UserService 中注入 UserDao,由于两者都没有声明 scope,所以默认都是单例的。
现在,如果我给 UserDao 设置 Scope,如下:
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 Initializr 是 Spring 官方提供的一个用于快速创建和初始化 Spring 项目的在线工具。它可以让开发人员选择所需的 Spring 模块、版本、语言(Java、Kotlin 或 Groovy)和构建工具(Maven 或 Gradle),并生成一个基本的项目结构。现在大多数 IDE 都对 Spring Initializr 提供了支持!
官方的 Spring Initializr 服务(start.spring.io)部署在海外,在国内访问经常出现各种连网络接失败的问题。好在 Spring Initializr 是一个开源的项目,我们可以用它来构建自己的 Spring Initializr 服务。
Spring Initializr Github 仓库:https://github.com/spring-io/start.spring.io
构建 Spring Initializr 服务 Clone 项目 需要先在机器上安装 git 软件。
git clone https://github.com/spring-io/start.spring.io.git 该仓库下有三个工程,我们只关心其中2个:
start-client 前端工程,使用 React 开发。 start-site 后端工程,是一个 Spring Boot 应用。 执行构建 项目使用 maven 构建,且提供了 mvnw(Maven Wrapper) 脚本,它是一个用于管理和运行 Maven 项目的工具。它的作用是在没有全局安装 Maven 的情况下,通过自动下载和配置特定版本的 Maven 来确保项目的构建和运行环境一致性。也就是说 不需要在本地安装 Maven,通过此脚本即可完成构建。
进入项目根目录,执行如下命令进行自动构建: