Spring Boot @ConditionalOnThreading 注解

1、简介 本文将带你了解一个相对较新的 Spring Boot 条件注解 @ConditionalOnThreading。 2、条件注解 条件注解提供了一种仅在满足各种特定条件时才在 BeanFactory 中注册 Bean 的方法。开发人员通过使用 Condition 接口为每个注解单独定义这些条件。 Spring Boot 为常见用例提供了大量预定义的条件注解。常见的示例有 @ConditionalOnProperty、@ConditionalOnBean 和 @ConditionalOnClass。 3、@ConditionalOnThreading 原理 @ConditionalOnThreading 只是 Spring Boot 中另一个预定义的条件注解。它是在 3.2 版本中添加的,在本文撰稿时,该版本本身还是候选发布版。也就是说,需要使用专用的 Spring Artifacts 仓库。 <repositories> <repository> <id>spring-milestones</id> <name>Spring Milestones</name> <url>https://repo.spring.io/milestone</url> <snapshots> <enabled>false</enabled> </snapshots> </repository> <repository> <id>spring-snapshots</id> <name>Spring Snapshots</name> <url>https://repo.spring.io/snapshot</url> <releases> <enabled>false</enabled> </releases> </repository> </repositories> <pluginRepositories> <pluginRepository> <id>spring-milestones</id> <name>Spring Milestones</name> <url>https://repo.spring.io/milestone</url> <snapshots> <enabled>false</enabled> </snapshots> </pluginRepository> <pluginRepository> <id>spring-snapshots</id> <name>Spring Snapshots</name> <url>https://repo.spring.io/snapshot</url> <releases> <enabled>false</enabled> </releases> </pluginRepository> </pluginRepositories> @ConditionalOnThreading 注解仅允许在 Spring 内部配置为使用特定类型的线程时创建 Bean。所谓线程类型,是指平台线程或虚拟线程。回顾一下,从 Java 21 开始,我们就可以 使用虚拟线程来代替平台线程 了。

国际化 Bean Validation 校验失败的错误消息

1、概览 在 Web 应用中,我们通常需要通过 spring-validation 对客户端提交的数据进行校验。如果校验失败则会抛出异常。默认情况下,关于校验失败细节的异常信息是英文。本文将会带你了解如何对校验失败时的异常消息进行国际化(也称为“本地化”)。 2、依赖 首先在 pom.xml 中添加 Spring Boot Starter Web 和 Spring Boot Starter Validation: <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> </dependency> 最新版本可在 Maven Central 上找到。 3、本地化信息存储 在 Java 应用中,通常使用 properties 文件存储本地化信息。一般称为 Resource Bundle。 这些文件是由键值对组成的纯文本文件。key 是信息检索的标识符,而对应的 value 则是相应语言的本地化消息。 接下来,我们创建 2 个 properties 文件。 CustomValidationMessages.properties 是默认的 properties 文件,文件名不包含任何语言名称。只要客户端指定的语言不支持,应用就会使用默认语言: field.personalEmail=Personal Email validation.notEmpty={field} cannot be empty validation.email.notEmpty=Email cannot be empty 再创建一个额外的中文语言的 properties 文件 - CustomValidationMessages_zh.properties。只要客户端指定 zh 或 zh-tw 等变体作为本地语言,应用语言就会切换为中文:

Spring Boot 整合 Kafka Stream

1、简介 流式数据在现实生活中的一些例子包括传感器数据、股票市场事件流和系统日志。在本文中,我们通过构建一个简单的字数统计流式应用来介绍如何在 Spring Boot 中使用 Kafka Streams。 2、概览 Kafka Streams 在 Kafka Topic 和关系型数据库表之间提供了一种对偶性。它使我们能够对一个或多个流式事件进行连接、分组、聚合和过滤等操作。 Kafka 流的一个重要概念是处理器拓扑(Processor Topology)。处理器拓扑是 Kafka Stream 对一个或多个事件流进行操作的蓝图。从本质上讲,处理器拓扑可视为有向无环图。在这个图中,节点分为源节点、处理器节点和汇节点,而边则代表流事件的流向。 位于拓扑结构顶端的源接收来自 Kafka 的流数据,将其向下传递到执行自定义操作的处理器节点,并通过汇节点流出到新的 Kafka Topicc。在进行核心处理的同时,还利用检查点(Checkpoint)定期保存数据流的状态,以实现容错和弹性。 3、依赖 首先在 POM 中添加 spring-kafka 和 kafka-streams 依赖: <dependency> <groupId>org.springframework.kafka</groupId> <artifactId>spring-kafka</artifactId> <version>2.7.8</version> </dependency> <dependency> <groupId>org.apache.kafka</groupId <artifactId>kafka-streams</artifactId> <version>2.7.1</version> </dependency> 4、示例 示例应用从输入的 Kafka Topic 中读取流式事件。读取记录后,它会对记录进行处理,分割文本并计算单个字数。随后,它将更新的字数发送到 Kafka 输出。除了输出 Topic 外,还要创建一个简单的 REST 服务,通过 HTTP 端点公开该计数。 总之,输出 Topic 将不断更新从输入事件中提取的单词及其更新计数。 4.1、配置 在 Java 配置类中定义 Kafka Stream 配置: @Configuration @EnableKafka @EnableKafkaStreams public class KafkaConfig { @Value(value = "${spring.

Spring Boot 启动加速

1、简介 本文将带你了解如何通过调整 Spring 应用的配置、JVM 参数和使用 GraalVM 原生镜像来缩短 Spring Boot 的启动时间。 2、调整 Spring 应用 首先,创建一个 Spring Boot(2.5.4)应用,添加 Spring Web、Spring Actuator 和 Spring Security 依赖。 还要添加 spring-boot-maven-plugin 插件,并配置将应用打包到 jar 文件中: <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <version>${spring-boot.version}</version> <configuration> <finalName>springStartupApp</finalName> <mainClass>com.baeldung.springStart.SpringStartApplication</mainClass> </configuration> <executions> <execution> <goals> <goal>repackage</goal> </goals> </execution> </executions> </plugin> 使用标准的 java -jar 命令运行 jar 文件,并查看应用的启动时间。 c.b.springStart.SpringStartApplication : Started SpringStartApplication in 3.403 seconds (JVM running for 3.961) 如上,应用启动时间约为 3.4 秒。我们把这个时间作为下文调整的参考。 2.1、延迟初始化 Spring 支持延迟初始化。延迟初始化意味着 Spring 不会在启动时创建所有 Bean。此外,Spring 在需要 Bean 之前不会注入任何依赖。从 Spring Boot 2.

在 Spring Boot 中配置主从数据库实现读写分离

前言 现在的 Web 应用大都是读多写少。除了缓存以外还可以通过数据库 “主从复制” 架构,把读请求路由到从数据库节点上,实现读写分离,从而大大提高应用的吞吐量。 通常,我们在 Spring Boot 中只会用到一个数据源,即通过 spring.datasource 进行配置。前文 《在 Spring Boot 中配置和使用多个数据源》 介绍了一种在 Spring Boot 中定义、使用多个数据源的方式。但是这种方式对于实现 “读写分离” 的场景不太适合。首先,多个数据源都是通过 @Bean 定义的,当需要新增额外的从数据库时需要改动代码,非常不够灵活。其次,在业务层中,如果需要根据读、写场景切换不同数据源的话只能手动进行。 对于 Spring Boot “读写分离” 架构下的的多数据源,我们需要实现如下需求: 可以通过配置文件新增数据库(从库),而不不需要修改代码。 自动根据场景切换读、写数据源,对业务层是透明的。 幸运的是,Spring Jdbc 模块类提供了一个 AbstractRoutingDataSource 抽象类可以实现我们的需求。 它本身也实现了 DataSource 接口,表示一个 “可路由” 的数据源。 核心的代码如下: public abstract class AbstractRoutingDataSource extends AbstractDataSource implements InitializingBean { // 维护的所有数据源 @Nullable private Map<Object, DataSource> resolvedDataSources; // 默认的数据源 @Nullable private DataSource resolvedDefaultDataSource; // 获取 Jdbc 连接 @Override public Connection getConnection() throws SQLException { return determineTargetDataSource().

Spring Security 配置 Content Security Policy(CSP)

1、概览 跨站脚本攻击(Cross-Site Scripting,XSS)一直稳居最常见的 十大网络攻击 之列。XSS 攻击发生在 Web 服务器处理用户恶意输入时,未经验证或编码即在页面上渲染。与 XSS 攻击类似,代码注入和点击劫持通过窃取用户数据和冒充用户身份来对 Web 应用造成严重影响。 本文将会带你了解如何使用 Spring Security 通过内容安全策略(Content-Security-Policy)保护 Web 应用免受点击劫持、代码注入和 XSS 攻击。 2、Content Security Policy 内容安全策略(Content Security Policy,简称 CSP)是一种 HTTP 响应头,可大大减少 现代浏览器 中的代码注入攻击,如 XSS、点击劫持 等。 Web 服务器通过 Content-Security-Policy Header 部指定了浏览器可以渲染的资源的列表。这些资源可以是浏览器渲染的任何内容,例如 CSS、JavaScript、图像等。 该 Header 的语法如下: Content-Security-Policy: <directive>; <directive>; <directive> ; ... 此外,还可以将此策略设置为 HTML 页面中 <meta> 标签的一部分: <meta http-equiv="Content-Security-Policy" content="<directive>;<directive>;<directive>; ..."> 每个 指令 都包含一个具有多个值的 key。指令可以不止一个,每个指令之间用分号(;) 分隔: Content-Security-Policy: script-src 'self' https://baeldung.com; style-src 'self'; 如上例所示,有两个指令(script-src 和 style-src),而指令 script-src 有两个值(self 和 https://baeldung.

Spring Cloud Load Balancer 指南

1、简介 随着微服务架构越来越流行,在不同服务器上运行多个服务变得越来越普遍。本文将带你了解如何使用 Spring Cloud Load Balancer(负载均衡器) 创建容错性更强的应用。 2、负载均衡是什么? 负载均衡是在同一应用的不同实例之间分配流量的过程。 为了容错,每个应用通常都要运行多个实例。因此,当一个服务需要与另一个服务通信时,它需要选择一个特定的实例来发送请求。 负载均衡,有很多算法: 随机选择:随机选择一个实例 循环:每次按相同顺序选择实例 最少连接:选择当前连接最少的实例 权重指标:使用权重指标选择最佳实例(例如 CPU 或内存使用率) IP 哈希(Hash):使用客户端 IP 的哈希值映射到实例 以上只是负载均衡算法的几个例子,每种算法都有其优缺点。 随机选择和轮循很容易实现,但可能无法优化服务的使用。相反,最少连接和权重指标比较复杂,但通常能创造更优化的服务利用率。IP 哈希可以保证客户端每次都命中同一台实例,意味着实例可以保存一些客户端的状态信息,但它的容错性不强。 3、Spring Cloud Load Balancer 简介 Spring Cloud Load Balancer 用来创建以负载均衡方式与其他应用通信的应用。可以使用任意算法,在进行远程服务调用时轻松实现负载均衡。 接下来,我们通过实例来进行说明。首先,创建一个简单的服务器应用。服务器只有一个 HTTP 端点,可以作为多个实例运行。 然后,创建一个客户端应用,使用 Spring Cloud Load Balancer 在服务器的不同实例之间轮流发送请求。 3.1、示例服务器 创建一个简单的 Spring Boot 应用: @SpringBootApplication @RestController public class ServerApplication { public static void main(String[] args) { SpringApplication.run(ServerApplication.class, args); } @Value("${server.instance.id}") String instanceId; @GetMapping("/hello") public String hello() { return String.

JUnit 测试时加载 ApplicationContext 失败

1、概览 在 Spring Boot 应用中,可以同时包含基于注解和基于 XML 的配置来混合定义 Bean。在这种环境中,如果你在测试类中使用基于 XML 的配置可能会遇到 “Failed to load ApplicationContext” 异常。因为 Application Context 没有加载到 Test Context 中。 本文将会带你了解如何把 XML Application Context 集成到 Spring Boot 应用的测试中。 2、“Failed to load ApplicationContext” 异常 在 Spring Boot 应用中集成基于 XML 的 Application Context 来重现该异常。 首先,假设有一个包含 Service Bean 定义的 application-context.xml 文件: <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="employeeServiceImpl" class="com.baeldung.xmlapplicationcontext.service.EmployeeServiceImpl" /> </beans> 在 webapp/WEB-INF/ 位置添加 application-context.xml 文件: 再创建一个 Service 接口和实现类:

Spring Cloud Gateway 和 Oauth2

1、概览 Spring Cloud Gateway 是一个响应式的轻量级网关,是 Spring Cloud 体系中一个比较重要的组件。本文将带你了解如何在其基础上快速实现 OAuth 2.0 认证、授权。 2、OAuth 2.0 快速回顾 OAuth 2.0 标准是一个成熟的标准,在互联网上广泛使用,是用户和应用安全访问资源的一种安全机制。 其中涉及的关键术语如下: Resource(资源):只有经过授权的客户端才能检索的任何类型的信息。 Client(客户端):消费资源的应用,通常通过 REST API 消费资源。 Resource Server(资源服务器):负责向授权客户端提供资源的服务。 Resource Owner(资源所有者):实体(人或应用),拥有资源,并最终负责向客户端授予对该资源的访问权限。 Token(令牌):客户端获取的一段信息,并作为请求的一部分发送给资源服务器以进行身份验证。 Identity Provider(身份提供商,即 IDP):验证用户凭证并向客户端发放 Access Token。 Authentication Flow(认证模式/流程):客户端获得有效 Token 必须经过的一系列步骤。 你可以通过 Auth0 的相关文档了解更多详细内容。 3、OAuth 2.0 模式 Spring Cloud Gateway 主要用于以下用途之一: OAuth Client(客户端) OAuth Resource Server(资源服务器) 我们来逐个了解。 3.1、Spring Cloud Gateway 作为 OAuth 2.0 客户端 在这种情况下,任何未经身份认证的传入请求都将触发授权码流程。一旦网关获取到 Token,它将在向后端服务发起请求时使用该 Token。 在实际应用中,一个很好的例子是聚合了 “社交应用” 的应用:对于每个支持的社交应用,网关将充当 OAuth 2.0 客户端。 因此,前端(通常是使用 Angular、React 或类似 UI 框架构建的 SPA 应用)可以代表终端户无缝访问这些应用上的数据。更重要的是:用户无需暴露自己的凭证。

在 Swagger 文档中移除 BasicErrorController

1、概览 本文将带你了解如何 Swagger 文档界面中隐藏 BasicErrorController。 3、问题 如果应用中包含了一个 BasicErrorController,Swagger 默认会将其所有端点也包含在生成的文档中。 我们需要提供自定义配置来移除不需要的 Controller。 例如,项目中的 Rest Controller 如下: @RestController @RequestMapping("good-path") public class RegularRestController { @ApiOperation(value = "This method is used to get the author name.") @GetMapping("/getAuthor") public String getAuthor() { return "Name Surname"; } } 另外,还包含一个继承 BasicErrorController 的 Error Controller: @Component @RequestMapping("my-error-controller") public class MyErrorController extends BasicErrorController { // basic constructor } 启动应用,访问文档!你可以看到,my-error-controller 包含在生成的文档中: 4、解决办法 有四种方式可以从 Swagger 文档中排除资源。 4.1、通过 basePackage() 方法排除 通过指定 Controller 所在的包,可以排除其他不需要的资源。