教程

Spring Cloud Gateway 与 Netflix Zuul 2:2025 年 API 网关选型指南

API 网关在微服务架构中至关重要,负责路由、负载均衡、安全防护和可观测性。Java 生态中有两大主流方案: Spring Cloud Gateway(SCG)—— Spring 团队提供的现代化响应式方案。 Netflix Zuul 2 —— Zuul 的升级版,专为异步非阻塞 I/O 设计。 但 2025 年哪种更胜一筹?本文将从性能、功能特性和实际适用性进行对比,助你决策。 1、性能对比 基准测试结果(延迟与吞吐量) 指标 Spring Cloud Gateway Netflix Zuul 2 平均延迟(毫秒) 12 25 最大吞吐量(请求数/秒) 15,000 8,000 CPU 使用率 更低(响应式技术栈) 更高(基于 Servlet) 🔹 为何 Spring Cloud Gateway 胜出? 基于 Project Reactor(非阻塞式)。 无 Servlet 容器开销(与 Zuul 2 不同)。 专为 云原生负载 优化。 🔹 何时 Zuul 2 更合适? 若已深度集成 Netflix OSS 生态。 需更精细的过滤器(Zuul 2 内置过滤器更丰富)。 2、功能特性对比 功能特性 Spring Cloud Gateway Netflix Zuul 2 协议支持 HTTP/2、WebSockets HTTP/1.

Spring Email(邮件)发送指南

1、概览 本文将带你了解如何通过标准 Spring 应用及 Spring Boot 应用发送邮件。前者基于 JavaMail 库实现,后者则使用 spring-boot-starter-mail 依赖。 2、Maven 依赖 首先需在 pom.xml 中添加依赖。 2.1、Spring 以下是标准 Spring 框架所需的依赖配置: <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>6.1.5</version> </dependency> 最新版本可在 此处 获取。 2.2、Spring Boot 而 Spring Boot 则需要添加: <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-mail</artifactId> <version>3.1.5</version> </dependency> 最新版本可在 Maven 中央仓库 获取。 3、邮件服务器配置属性 Spring 框架中邮件支持的接口与类按以下结构组织: MailSender 接口:顶层接口,提供发送简单邮件的基础功能。 JavaMailSender 接口:MailSender 的子接口,支持 MIME 消息,通常与。MimeMessageHelper 类配合创建 MimeMessage。建议通过 MimeMessagePreparator 机制使用该接口。 JavaMailSenderImpl 类:实现 JavaMailSender 接口,支持 MimeMessage 和 SimpleMailMessage。 SimpleMailMessage 类:用于创建包含发件人、收件人、抄送、主题和文本内容的简单邮件。 MimeMessagePreparator 接口:为 MIME 消息提供准备机制的回调接口。 MimeMessageHelper 类:创建 MIME 消息的辅助类,支持图片、典型邮件附件及 HTML 格式的文本内容。 以下章节将演示如何使用这些接口与类。

Java 关闭 Scanner 的最佳实践

1、简介 当使用 Java 的 Scanner 类读取 System.in(标准输入)输入时,部分 IDE 会提示可能存在资源泄漏。 例如,若未显式关闭 Scanner,可能收到警告:“Resource leak: ‘scanner’ is never closed”。但关闭关联 System.in 的 Scanner 需谨慎处理,以避免意外问题。 本文将带你了解关闭 Scanner 的重要性及在 Java 中的正确操作方式。 2、理解 IDE 提示的异常 在 Java 中,使用文件、网络连接(Socket)和输入流等资源后应关闭资源以释放系统内存。Scanner 类从文件或 System.in 等源读取原始值和字符串输入,由于实现了 Closeable 接口,因此它持有的资源需要在不使用时及时释放。 部分 IDE(如 Eclipse 和 Visual Studio Code)若检测到未正确关闭 Scanner 对象,会显示如下资源泄漏警告: 3、通过 close() 方法关闭 Scanner 在 Java 中,可通过 close() 方法关闭 Scanner 以释放系统资源,这在读取文件或 System.in 时尤为重要。 建议在 finally 代码块中关闭 Scanner,确保即使发生异常也能正确释放资源,避免泄漏: @Test void givenUserName_whenGetGreetingMessage_thenReturnsWelcomeMessage() { String input = "Anees\n"; ByteArrayInputStream inputStream = new ByteArrayInputStream(input.

使用 Spring 发送邮件时异常“Could Not Autowire org.springframework.mail.javamail.JavaMailSender”

1、简介 本文将带你了解使用 Spring Boot 实现邮件功能时遇到 “Could not autowire org.springframework.mail.javamail.JavaMailSender” 异常的原因以及解决办法。 2、理解异常 首先解释该错误的含义。JavaMailSender 是 Spring 提供的接口,用于抽象邮件发送过程。它继承自 MailSender 接口(提供简单文本邮件的基础功能),特别支持 MIME 消息、附件和 HTML 内容等高级特性。 Spring 的依赖注入机制会自动装配所需 Bean。当遇到 @Autowired 注解或更推荐的构造器注入时,它会从应用上下文(Application Context)中查找匹配的 Bean: @Service public class EmailService { private final JavaMailSender javaMailSender; public EmailService(final JavaMailSender javaMailSender) { this.javaMailSender = javaMailSender; } } 当我们注入 Spring 无法找到的 JavaMailSender Bean 并运行应用时,会抛出以下错误: Field javaMailSender in com.baeldung.email.EmailService required a bean of type 'org.springframework.mail.javamail.JavaMailSender' that could not be found. 或者: Parameter 0 of constructor in com.

Gson 中的 @Expose 与 @SerializedName 注解

1、简介 Gson 是 Google 开发的开源 Java 库,用于简化对象与 JSON 之间的转换。它提供高效的序列化与反序列化技术,并支持复杂对象处理。 像 Gson 这样的库支持将 JSON 直接映射到 POJO。但某些场景下需要排除特定属性的序列化与反序列化。 本文将带你了解 Gson 库中两个关键注解:@Expose 和 @SerializedName。尽管二者均涉及属性的序列化控制,但适用场景不同。 2、Gson 设置 要使用 Gson,需在 pom.xml 中添加其 Maven 依赖: <dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> <version>2.10.1</version> </dependency> 3、@Expose 注解 Gson 默认会序列化和反序列化 POJO 类的所有字段,除非另有指定。@Expose 注解可覆盖此行为,控制特定字段是否参与序列化或反序列化。 若字段的 serialize 和 deserialize 属性设为 true,Gson 仅会处理带有 @Expose 注解的字段。这两个属性的默认值均为 true。 以下示例展示了一个包含 id、name、age 和 email 的 User 类。由于 email 是敏感信息,我们将其从输出的 JSON 中排除: public class User { @Expose String name; @Expose int age; @Expose(serialize = true, deserialize = false) long id; @Expose(serialize = false, deserialize = false) private String email; // 构造函数、Getter、Setter 省略 } 在上述代码片段中,我们用 @Expose 标注了 name 和 age 字段。未显式设置 serialize 和 deserialize 属性意味着它们默认为 true。

JVM 中的参数前缀

1、概览 Java 虚拟机(JVM)是驱动 Java 应用的核心引擎,负责执行编译后的 .class 文件,并通过即时编译(JIT)和垃圾回收(GC)等技术管理内存并提升性能。 JVM 具有高度灵活性,通过特定参数可轻松调整其行为以提升性能、排查问题或启用实验性功能。本文将带你了解用于配置 JVM 的不同参数前缀。 2、JVM 参数是什么? JVM 参数是能改变虚拟机行为的特殊命令行选项,用于控制内存设置、性能调优、调试监控开关、垃圾回收配置及实验性功能。 启动 JVM 时可通过以下方式指定这些参数: java -Xmx512m -Denv=prod -verbose:gc -XX:+UseG1GC -jar App.jar 上述命令中使用了多种参数前缀,每个前缀标识了不同的配置类型。 -Xmx512m - 设置最大堆内存为 512 MB(非标准参数) -Denv=prod - 定义名为 env、值为 prod 的系统属性(System Property) -verbose:gc - 启用垃圾回收日志记录(标准参数) -XX:+UseG1GC - 指定 JVM 使用 G1 垃圾回收器(高级参数) 下面详细解析各类参数前缀的作用。 3、不同的 JVM 参数前缀 3.1、System Properties (-D) 系统属性(System Properties)通常用于配置 JVM 特定参数,如文件编码、用户目录、JVM 版本等 Java 相关配置。 通过 -D 命令行参数可定义键值对形式的系统属性,例如: java -Denv=prod -jar App.jar 在 -D 参数前缀中,字母 D 代表 Define(定义)。Java 为避免歧义未使用其他字母,该前缀简短、直观且易记忆,明确表示正在定义属性。

过滤 HTML 代码以防止 XSS 攻击的几种方案

1、简介 跨站脚本攻击(XSS)是一种安全漏洞,允许攻击者向网页应用中注入恶意脚本。这些脚本能在用户浏览器中执行,导致数据窃取、会话劫持或页面篡改等风险。 本文将带你了解如何在 Java 应用中过滤 HTML 输入以防止 XSS 攻击。 2、项目设置 首先,需要在 pom.xml 中添加 OWASP Java HTML sanitizer 库: <dependency> <groupId>com.googlecode.owasp-java-html-sanitizer</groupId> <artifactId>owasp-java-html-sanitizer</artifactId> <version>20240325.1</version> </dependency> 该库提供高度可配置的策略驱动式 Sanitizer(净化器),既能处理复杂 HTML 内容,又能有效防御 XSS 攻击。 3、实现基础版 OWASP HTML 过滤 添加依赖后,我们定义一个工具方法,利用该库清理可能非法的 HTML 输入。 以下创建了一个可复用的工具类,采用默认策略(仅允许基础格式化标签)实现 HTML 过滤: public class HtmlSanitizerUtil { private static final PolicyFactory POLICY = Sanitizers.FORMATTING.and(Sanitizers.LINKS); public static String sanitize(String htmlContent) { return POLICY.sanitize(htmlContent); } } 上例中,我们通过组合两个内置 Sanitizer(Sanitizers.FORMATTING 和 Sanitizers.LINKS)配置过滤策略。该策略允许基础 HTML 格式化标签(如 <b>、<i>、<u>)以及通过 <a> 标签实现的超链接。随后 sanitize() 方法将此策略应用于输入字符串,返回过滤后的 HTML 内容。

如何在 Mapstruct 中进行嵌套映射?

1、概览 MapStruct 通过注解来定义 POJO 属性间的映射关系。其 Maven 插件会读取注解中定义的元数据,自动生成 Mapper 工具类。此外,它还支持通过自定义映射工具实现细粒度控制。 本文将带你了解如何用 MapStruct 将层次化的源实体嵌套属性映射到扁平化的目标实体 2、用例 类体系图如下。通过源实体 Order 和目标实体 OrderDto 来演示 MapStruct 库执行嵌套映射的能力: 源实体 Order 表示具有嵌套结构的复杂对象,包含 Customer 和 Product: public class Order { private Customer customer; private Product product; // Getter/Setter 省略 } public class Customer { private String name; private Address address; // Getter/Setter 省略 } public class Product { private String name; private double price; // Getter/Setter 省略 } 此外,Customer 实体具有一个类型为 Address 的 address 属性:

Hibernate 异常 “DuplicateMappingException: Column is duplicated in mapping for entity”

1、概览 本文将带你了解如何处理 Hibernate 异常 “DuplicateMappingException: Column is duplicated in mapping for entity”。 2、理解 DuplicateMappingException 简而言之,DuplicateMappingException 是 MappingException 的子类,专门用于处理重复的对象关系映射错误。 当实体类中多次映射同一列时,会出现 “Column is duplicated in mapping for entity” 的提示信息。这种情况下,Hibernate 无法处理这种重复映射。 3、重现 DuplicateMappingException 了解了导致 Hibernate 抛出 DuplicateMappingException 的原因后,让我们通过实践来复现这个问题。 首先,定义一个 Person 实体类: @Entity public class Person { @Id private int id; @Column(name = "first_name") private String firstName; @Column(name = "first_name") // 重复定义了 first_name 列 private String lastName; // 省略 Getter/Setter } 简而言之,一个 person 由 id、firstName 和 lastName 组成。@Entity 注解表明 Person 类是一个 JPA 实体,而 @Id 注解表示主键。此外,@Column 注解将每个实体字段映射到特定的表列。

在 Docker Compose 中让容器保持运行

1、概览 一个 Docker 容器会运行一个进程、应用程序,有时仅是一个脚本或命令,以执行其设计任务。 每个容器一旦内部没有任何进程或脚本运行,就会停止并退出。有些容器默认会持续运行,直到用户选择停止它们,例如 MySQL 数据库容器、Spring Boot Web 应用容器或 SMTP 邮件服务器容器。但有时,我们需要让容器在其主要任务完成后仍然保持运行,比如 Ubuntu 容器。 本文将带你了解如何使用 Docker Compose 实现这一需求。 2、Docker Compose 设置 Docker Compose 是我们用来定义和运行多容器服务的工具。唯一的前提条件是在受支持的操作系统平台上安装 Docker(包括 Docker Server、Docker Client 和 Docker Compose)。 本教程中我们使用 Linux Ubuntu。 3、运行 Ubuntu 容器 我们使用一个名为 docker-compose.yml 的示例 Docker Compose 配置文件来定义服务: services: demo: image: ubuntu 3.1、启动 Docker Compose 服务 使用 -d 选项在后台运行服务的容器: $ docker-compose up -d 输出如下,显示它创建了一个容器: Creating ubuntu_demo_1 ... done 查看 Docker Compose 服务创建的容器是否正在运行。 使用 docker ps -a 命令列出容器: