电子书 – Spring Cloud 指南 – NPI EA (分类=Spring Cloud)
announcement - icon

让我们开始使用 Spring Cloud 的微服务架构

>> 加入 Pro 并下载电子书

电子书 – Mockito – NPI EA (标签 = Mockito)
announcement - icon

模拟是单元测试的重要组成部分,Mockito 库使编写 清晰直观的单元测试 变得容易,用于您的 Java 代码。

通过我们的 Mockito 指南 开始模拟,并改进您的应用程序测试

下载电子书

电子书 – Java 并发 – NPI EA (分类=Java 并发)
announcement - icon

在应用程序中处理并发可能是一个棘手的过程,其中包含许多 潜在的陷阱。 扎实的掌握基本知识将有助于最大程度地减少这些问题。

通过我们的 Java 并发 指南开始了解多线程应用程序

>> 下载电子书

电子书 – 响应式 – NPI EA (分类=响应式)
announcement - icon

Spring 5 增加了对使用 Spring WebFlux 模块进行响应式编程的支持,此支持自那时起不断改进。 开始使用 Reactor 项目基础知识和 Spring Boot 中的响应式编程

>> 加入 Pro 并下载电子书

电子书 – Java Streams – NPI EA (分类=Java Streams)
announcement - icon

自从 Java 8 引入以来,Stream API 已成为 Java 开发的基础。 基本操作,例如迭代、过滤、映射元素序列,使用起来看似很简单。

但这些也可能被过度使用并陷入一些常见陷阱。

更好地了解 Stream 的工作方式 以及如何将其与其他语言功能结合使用,请查看我们关于 Java Streams 的指南

>> 加入 Pro 并下载电子书

电子书 – Jackson – NPI EA (分类=Jackson)
announcement - icon

用 Jackson 正确处理 JSON

下载电子书

电子书 – HTTP 客户端 – NPI EA (分类=Http 客户端)
announcement - icon

充分利用 Apache HTTP 客户端

下载电子书

电子书 – Maven – NPI EA (分类 = Maven)
announcement - icon

开始使用 Apache Maven

下载电子书

电子书 – 持久化 – NPI EA (分类=持久化)
announcement - icon

您在努力实现正确的持久化层 Spring 吗?

探索电子书

电子书 – RwS – NPI EA (分类=Spring MVC)
announcement - icon

使用 Spring 构建 REST API 吗?

下载电子书

课程 – LS – NPI EA (分类=Jackson)
announcement - icon

通过 Learn Spring 课程开始学习 Spring 和 Spring Boot

>> 学习 SPRING
课程 – RWSB – NPI EA (分类=REST)
announcement - icon

通过构建一个完整的 REST API,深入了解 Spring Boot 3 和 Spring 6,使用该框架

>> 全新的“REST With Spring Boot”

课程 – LSS – NPI EA (分类=Spring Security)
announcement - icon

是的,Spring Security 可能很复杂,从核心内的更高级功能到框架中深入的 OAuth 支持。

我将安全材料构建为 两个完整的课程 - 核心和 OAuth,以针对这些更复杂的场景进行实践。 我们探索何时以及如何使用每个功能,并 在后台项目中对其进行编码

您可以在这里探索该课程

>> 学习 Spring Security

课程 – LSD – NPI EA (标签=Spring Data JPA)
announcement - icon

Spring Data JPA 是处理 JPA 复杂性的绝佳方式,它具有 Spring Boot 的强大简洁性

通过引导式参考课程开始使用 Spring Data JPA

>> 查看课程

合作伙伴 – Moderne – NPI EA (类别=Spring Boot)
announcement - icon

使用 OpenRewrite 安全且自动地重构 Java 代码。

手动重构大型代码库既缓慢、有风险,又容易拖延。OpenRewrite 应运而生。这个用于大规模、自动化代码转换的开源框架可以帮助团队安全、一致地进行现代化改造。

每个月,OpenRewrite 的创建者和维护者 Moderne 都会举办现场、实践培训课程——一个面向初学者,一个面向经验丰富的用户。您将了解配方的运作方式、如何将其应用于项目,以及如何自信地进行代码现代化改造。

参加下一次课程,带来您的问题,并学习如何自动化通常会占用您 sprint 时间的工作。

合作伙伴 – LambdaTest – NPI EA (类别=测试)
announcement - icon

回归测试是发布流程中的重要步骤,以确保新代码不会破坏现有功能。随着代码库的不断发展,我们希望频繁运行这些测试,以便尽早发现任何问题。

确保这些测试以自动化的方式频繁运行的最佳方法当然是将其包含在 CI/CD 管道中。 这样,每次向仓库提交代码时,回归测试将自动执行。

在本教程中,我们将学习如何使用 Selenium 创建回归测试,然后使用 GitHub Actions 将它们包含在我们的管道中,在 LambdaTest 云网格上运行

>> 如何使用 GitHub Actions 运行 Selenium 回归测试

课程 – LJB – NPI EA (类别 = Core Java)
announcement - icon

通过编码方式构建 Java 的坚实、实用的基础

>> 学习 Java 基础

合作伙伴 – LambdaTest – NPI (类别 = 测试)
announcement - icon

回归测试是发布流程中的重要步骤,以确保新代码不会破坏现有功能。随着代码库的不断发展,我们希望频繁运行这些测试,以便尽早发现任何问题。

确保这些测试以自动化的方式频繁运行的最佳方法当然是将其包含在 CI/CD 管道中。 这样,每次向仓库提交代码时,回归测试将自动执行。

在本教程中,我们将学习如何使用 Selenium 创建回归测试,然后使用 GitHub Actions 将它们包含在我们的管道中,在 LambdaTest 云网格上运行

>> 如何使用 GitHub Actions 运行 Selenium 回归测试

课程 – LJU – NPI (标签 = JUnit)
announcement - icon

通过Learn JUnit课程掌握最流行的 Java 测试框架

>> 学习 JUnit

1. 概述

当我们单元测试依赖于环境变量的代码时,我们可能希望在测试实现中为其提供特定的值。

Java 不允许我们编辑环境变量,但我们可以使用一些解决方法,以及一些可以帮助我们的库。

在本教程中,我们将探讨在单元测试中依赖环境变量的挑战,Java 在最新版本中如何使这变得更加困难,以及 JUnit PioneerSystem StubsSystem Lambda 和 System Rules 库。我们将针对 JUnit 4JUnit 5TestNG 进行研究。

2. 更改环境变量的挑战

在其他语言(如 JavaScript)中,我们可以非常轻松地在测试中修改环境

beforeEach(() => {
   process.env.MY_VARIABLE = 'set';
});

Java 严格得多。在 Java 中,环境变量映射是不可变的。它是一个不可修改的 Map,在 JVM 启动时初始化。虽然这有充分的理由,但我们可能仍然希望在测试时控制我们的环境。

2.1. 为什么环境是不可变的

在 Java 程序的正常执行中,如果像运行时环境配置这样全局的东西可以被修改,可能会变得混乱。这尤其是在涉及多个线程时。例如,一个线程可能正在修改环境,同时另一个线程正在启动一个使用该环境的进程,任何冲突的设置都可能以意想不到的方式交互。

因此,Java 的设计者维护了环境变量映射中的全局值安全。相比之下,系统属性可以在运行时轻松更改

2.2. 解决不可修改的 Map 问题

对于不可变的环境变量 Map 对象,有一个解决方法。尽管它的只读 UnmodifiableMap 类型,我们可以打破封装并使用 反射 访问内部字段

Class<?> classOfMap = System.getenv().getClass();
Field field = classOfMap.getDeclaredField("m");
field.setAccessible(true);
Map<String, String> writeableEnvironmentVariables = (Map<String, String>)field.get(System.getenv());

UnmodifiableMap 包装对象内部的字段 m 是一个可变的 Map,我们可以更改它

writeableEnvironmentVariables.put("baeldung", "has set an environment variable");

assertThat(System.getenv("baeldung")).isEqualTo("has set an environment variable");

在实践中,在 Windows 上,ProcessEnvironment 的另一种实现方式也考虑了不区分大小写的环境变量,因此使用上述技术的库也必须考虑到这一点。但是,原则上,这就是我们可以解决不可变环境变量 Map 的方法。

JDK 16 之后,模块系统对 JDK 内部的保护更加严格,使用这种 反射访问 变得更加困难.

2.3. 当反射访问不起作用时

Java 模块系统默认情况下禁用对其核心内部的反射修改 自从 JDK 17。这些被认为是可能导致未来运行时错误的危险做法,因为内部结构可能会发生变化。

我们可能会收到如下错误

Unable to make field private static final java.util.HashMap java.lang.ProcessEnvironment.theEnvironment accessible: 
  module java.base does not "opens java.lang" to unnamed module @fdefd3f

这表明 Java 模块系统正在阻止使用反射。可以通过在 pom.xml 中的测试运行器配置中添加一些额外的命令行参数来使用 >–add-opens 来允许这种反射访问来解决此问题

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <configuration>
        <argLine>
            --add-opens java.base/java.util=ALL-UNNAMED
            --add-opens java.base/java.lang=ALL-UNNAMED
        </argLine>
    </configuration>
</plugin>

这种解决方法允许我们编写代码并使用通过反射破坏封装的工具。然而,我们可能希望避免这样做,因为这些模块的开放可能会允许不安全的编码实践,这些实践在测试时有效,但在运行时意外失败。我们可以选择不需要这种解决方法工具。

2.4. 我们需要以编程方式设置环境变量的原因

我们的单元测试可以设置由测试运行器设置的环境变量来运行。如果我们在整个测试套件中都有全局配置,这可能是我们的首选方案。

我们可以通过在我们的 pom.xml中的 surefire配置中添加一个环境变量来实现这一点

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <configuration>
        <environmentVariables>
            <SET_BY_SUREFIRE>YES</SET_BY_SUREFIRE>
        </environmentVariables>
    </configuration>
</plugin>

该变量随后对我们的测试可见

assertThat(System.getenv("SET_BY_SUREFIRE")).isEqualTo("YES");

然而,我们可能有一些代码,其行为取决于不同的环境变量设置。我们可能更喜欢能够测试这种行为的所有变体,在不同的测试用例中使用不同值的环境变量。

类似地,我们可能在测试时有无法在编码时预测的值。一个很好的例子是我们在哪里运行 WireMock或 在 docker 容器中测试数据库的端口。

2.5. 从测试库获得正确的帮助

有几个测试库可以帮助我们在测试时设置环境变量。每个库在与不同测试框架和 JDK 版本的兼容性方面都有自己的级别。

我们可以根据我们首选的工作流程,环境变量的值是否预先可知,以及我们计划使用的 JDK 版本来选择正确的库。

我们应该注意到,所有这些库都涵盖的不仅仅是环境变量。它们都采用捕获当前环境,然后在进行更改,并在测试完成后将环境恢复到原始状态的方法。

3. 使用 JUnit Pioneer 设置环境变量

JUnit Pioneer 是 JUnit 5 的一组扩展。它提供了一种基于注释的方式来设置和清除环境变量。

我们可以使用 junit-pioneer依赖项来添加它

<dependency>
    <groupId>org.junit-pioneer</groupId>
    <artifactId>junit-pioneer</artifactId>
    <version>2.1.0</version>
    <scope>test</scope>
</dependency>

3.1. 使用 SetEnvironmentVariable 注解

我们可以用 SetEnvironmentVariable 注解来注解一个测试类或方法,我们的测试代码将在设置了该值的环境中运行

@SetEnvironmentVariable(key = "pioneer", value = "is pioneering")
class EnvironmentVariablesSetByJUnitPioneerUnitTest {

}

我们应该注意, key 和 value 必须在编译时可知。

我们的测试然后可以使用环境变量

@Test
void variableCanBeRead() {
    assertThat(System.getenv("pioneer")).isEqualTo("is pioneering");
}

我们可以多次使用@SetEnvironmentVariable 注解来设置多个变量。

3.2. 清除环境变量

我们可能还希望清除系统提供的环境变量,甚至某些在类级别设置的环境变量,用于某些特定的测试

@ClearEnvironmentVariable(key = "pioneer")
@Test
void givenEnvironmentVariableIsClear_thenItIsNotSet() {
    assertThat(System.getenv("pioneer")).isNull();
}

3.3. JUnit Pioneer 的限制

JUnit Pioneer 只能与 JUnit 5 一起使用。 它使用反射,因此需要 Java 16 或更低的版本,或者采用add-opens 解决方法。

4. 使用 System Stubs 设置环境变量

System Stubs 对 JUnit 4、JUnit 5 和 TestNG 都有测试支持。与它的前身 System Lambda 类似,它也可以独立地在任何框架中任何测试代码的主体中使用。System Stubs 与从 JDK 11 开始的所有版本的 JDK 兼容

4.1. 在 JUnit 5 中设置环境变量

为此,我们需要 System Stubs JUnit 5 依赖项

<dependency>
    <groupId>uk.org.webcompere</groupId>
    <artifactId>system-stubs-jupiter</artifactId>
    <version>2.1.3</version>
    <scope>test</scope>
</dependency>

首先,我们需要将扩展添加到我们的测试类

@ExtendWith(SystemStubsExtension.class)
class EnvironmentVariablesUnitTest {
}

我们可以将一个EnvironmentVariables stub 对象初始化为测试类的一个字段,并设置我们想要使用的环境变量

@SystemStub
private EnvironmentVariables environment = new EnvironmentVariables("MY VARIABLE", "is set");

需要注意的是,我们必须使用@SystemStub 注解该对象,以便扩展知道如何处理它。

SystemStubsExtension 然后在测试期间激活这个替代环境,并在测试结束后清除它。在测试期间,EnvironmentVariables 对象也可以被修改,并且对System.getenv() 的调用会收到最新的配置。

我们还来看一个更复杂的情况,在这种情况下,我们希望设置一个仅在测试初始化时才知道其值的环境变量在这种情况下,由于我们将会在我们的beforeEach() 方法中提供一个值,所以我们不需要在初始化列表中创建该对象实例

@SystemStub
private EnvironmentVariables environmentVariables;

当 JUnit 调用我们的beforeEach() 时,扩展已经为我们创建了该对象,我们可以使用它来设置我们需要的环境变量

@BeforeEach
void beforeEach() {
    environmentVariables.set("systemstubs", "creates stub objects");
}

当我们的测试被执行时,环境变量将处于激活状态

@Test
void givenEnvironmentVariableHasBeenSet_thenCanReadIt() {
    assertThat(System.getenv("systemstubs")).isEqualTo("creates stub objects");
}

测试方法完成后,环境变量将恢复到修改前的状态。

4.2. 在 JUnit 4 中设置环境变量

为此,我们需要 System Stubs JUnit 4 依赖项

<dependency>
    <groupId>uk.org.webcompere</groupId>
    <artifactId>system-stubs-junit4</artifactId>
    <version>2.1.3</version>
    <scope>test</scope>
</dependency>

System Stubs 提供了一个 JUnit 4 规则。我们将它添加为测试类的一个字段

@Rule
public EnvironmentVariablesRule environmentVariablesRule =
  new EnvironmentVariablesRule("system stubs", "initializes variable");

这里我们已经用一个环境变量初始化了它。我们也可以在我们的测试期间,或者在我们的@Before 方法中调用 set() 来修改变量。

一旦测试运行,环境变量就会处于激活状态

@Test
public void canReadVariable() {
    assertThat(System.getenv("system stubs")).isEqualTo("initializes variable");
}

4.3. 在 TestNG 中设置环境变量

为此,我们需要 System Stubs TestNG 依赖项

<dependency>
    <groupId>uk.org.webcompere</groupId>
    <artifactId>system-stubs-testng</artifactId>
    <version>2.1.3</version>
    <scope>test</scope>
</dependency>

这提供了一个 TestNG 监听器,其工作方式与上述 JUnit 5 解决方案类似。

我们将监听器添加到我们的测试类

@Listeners(SystemStubsListener.class)
public class EnvironmentVariablesTestNGUnitTest {
}

然后我们添加一个用@SystemStub 注解的EnvironmentVariables 字段

@SystemStub
private EnvironmentVariables setEnvironment;

然后我们的beforeAll() 方法可以初始化一些变量

@BeforeClass
public void beforeAll() {
    setEnvironment.set("testng", "has environment variables");
}

并且我们的测试方法可以使用它们

@Test
public void givenEnvironmentVariableWasSet_thenItCanBeRead() {
    assertThat(System.getenv("testng")).isEqualTo("has environment variables");
}

4.4. 不使用测试框架的 System Stubs

System Stubs 最初基于 System Lambda 的代码库,后者带有只能在单个测试方法中使用的一些技术。这意味着测试框架的选择是完全开放的。

因此,System Stubs Core 可以用于在 JUnit 测试方法的任何位置设置环境变量。

首先,让我们获取 system-stubs-core 依赖项

<dependency>
    <groupId>uk.org.webcompere</groupId>
    <artifactId>system-stubs-core</artifactId>
    <version>2.1.3</version>
    <scope>test</scope>
</dependency>

现在,在我们的一个测试方法中,我们可以用一个构造来包围测试代码,该构造临时设置一些环境变量。首先我们需要从SystemStubs 静态导入

import static uk.org.webcompere.systemstubs.SystemStubs.withEnvironmentVariables;

然后我们可以使用withEnvironmentVariables() 方法来包装我们的测试代码

@Test
void useEnvironmentVariables() throws Exception {
    withEnvironmentVariables("system stubs", "in test")
      .execute(() -> {
          assertThat(System.getenv("system stubs"))
            .isEqualTo("in test");
      });
}

在这里我们可以看到assertThat() 调用是对一个已设置变量的环境的操作。在由 execute() 调用 Closure 之外,环境变量不会受到影响。

我们应该注意,此技术要求我们的测试在测试方法上具有throws Exception,因为execute() 函数必须处理可能调用带有已检查异常的方法的闭包。

此技术还要求每个测试设置自己的环境,如果我们要使用生命周期大于单个测试的测试对象(例如,Spring Context),则效果不佳。

System Stubs 允许其每个 stub 对象独立于测试框架进行设置和拆卸。因此,我们可以使用测试类的beforeAll()afterAll() 方法来操作我们的 EnvironmentVariables 对象

private static EnvironmentVariables environmentVariables = new EnvironmentVariables();

@BeforeAll
static void beforeAll() throws Exception {
    environmentVariables.set("system stubs", "in test");
    environmentVariables.setup();
}

@AfterAll
static void afterAll() throws Exception {
    environmentVariables.teardown();
}

然而,测试框架扩展的优势在于,它们可以避免这种样板代码,因为它们会为我们执行这些基本操作。

4.5. System Stubs 的限制

System Stubs 的 TestNG 功能仅在 2.1+ 版本中可用,这些版本仅限于 Java 11 及更高版本。

在它的 2.0 版本发布周期中,System Stubs 偏离了前面描述的基于反射的常用技术。它现在使用 ByteBuddy 来拦截环境变量调用。但是,如果项目使用的 JDK 版本低于 11,则也不需要使用这些较新的版本。

System Stubs 1.0 版本提供与 JDK 8 到 JDK 16 的兼容性。

5. System Rules 和 System Lambda

System Rules 是用于环境变量的最成熟的测试库之一,它为 JUnit 4 提供了设置环境变量的解决方案,它的作者用 System Lambda 取代它,以提供一种与测试框架无关的方法。它们基于相同的核心技术,用于在测试时替换环境变量。

5.1. 使用 System Rules 设置环境变量

首先我们需要 system-rules 依赖

<dependency>
    <groupId>com.github.stefanbirkner</groupId>
    <artifactId>system-rules</artifactId>
    <version>1.19.0</version>
    <scope>test</scope>
</dependency>

然后我们将规则添加到我们的 JUnit 4 测试类

@Rule
public EnvironmentVariables environmentVariablesRule = new EnvironmentVariables();

我们可以在我们的 @Before 方法中设置值

@Before
public void before() {
    environmentVariablesRule.set("system rules", "works");
}

并在我们的测试方法中访问正确的环境

@Test
public void givenEnvironmentVariable_thenCanReadIt() {
    assertThat(System.getenv("system rules")).isEqualTo("works");
}

规则对象 – environmentVariablesRule – 允许我们也在测试方法中立即设置环境变量。

5.2. 使用 System Lambda 设置环境变量

为此我们需要 system-lambda 依赖

<dependency>
    <groupId>com.github.stefanbirkner</groupId>
    <artifactId>system-lambda</artifactId>
    <version>1.2.1</version>
    <scope>test</scope>
</dependency>

如 System Stubs 解决方案中所示,我们可以将依赖于环境的代码放入测试中的闭包中。为此,我们应该静态导入 SystemLambda

import static com.github.stefanbirkner.systemlambda.SystemLambda.withEnvironmentVariable;

然后我们可以编写测试

@Test
void enviromentVariableIsSet() throws Exception {
    withEnvironmentVariable("system lambda", "in test")
      .execute(() -> {
          assertThat(System.getenv("system lambda"))
            .isEqualTo("in test");
      });
}

5.3. System Rules 和 System Lambda 的限制

虽然这两个库都比较成熟和广泛,但它们不能用于在 JDK 17 及更高版本中操作环境变量。

System Rules 严重依赖 JUnit 4。我们不能使用 System Lambda 设置测试范围广泛的环境变量,因此 它无法帮助我们初始化 Spring context

6. 避免模拟环境变量

虽然我们讨论了许多在测试时修改环境变量的方法,但可能值得考虑这是否必要,甚至是有益的。

6.1. 或许风险太高

如我们上面每个解决方案所示,在运行时更改环境变量并不简单。在存在多线程代码的情况下,情况可能会更加棘手。如果多个测试 fixture 在同一个 JVM 中并行运行,例如使用 JUnit 5 的并发 功能,那么存在不同测试尝试同时以矛盾的方式控制环境的风险。

虽然上面的一些测试库在多线程同时使用时可能不会崩溃,但很难预测环境变量在一瞬间如何被设置。更糟糕的是,一个线程可能会捕获另一个测试的临时环境变量,好像它们是所有测试完成后系统应该保持的正确状态一样。

例如,来自另一个测试库的例子,当Mockito 模拟静态方法时,它将该模拟限制在当前线程内,因为这种全局模拟会破坏并发测试。因此,修改环境变量会遇到完全相同的风险。一个测试会影响整个 JVM 的全局状态,并在其他地方引起副作用。

同样,如果我们运行的代码只能通过环境变量控制,那么测试起来可能非常困难,而且我们当然可以通过设计避免这种情况,对吗?

6.2. 使用依赖注入

测试一个在构造时接收所有输入,而不是从系统资源中获取输入的系统更容易。

诸如 Spring 之类的依赖注入容器允许我们构建易于与运行时隔离进行测试的对象。

我们还应该注意到,Spring 允许我们使用系统属性代替环境变量来设置其任何属性值。我们在此文章中讨论的每种工具也支持在测试时设置和重置系统属性。

6.3. 使用抽象

如果一个模块必须获取环境变量,也许它不应该直接依赖于 System.getenv(),而是可以使用一个环境变量读取器接口

@FunctionalInterface
interface GetEnv {
    String get(String name);
}

然后,系统代码可以通过构造函数注入该对象

public class ReadsEnvironment {
    private GetEnv getEnv;

    public ReadsEnvironment(GetEnv getEnv) {
        this.getEnv = getEnv;
    }

    public String whatOs() {
        return getEnv.get("OS");
    }
}

虽然在运行时,我们可能会使用 System::getenv来实例化它,但在测试时,我们可以传递我们自己的替代环境变量。

Map<String, String> fakeEnv = new HashMap<>();
fakeEnv.put("OS", "MacDowsNix");

ReadsEnvironment reader = new ReadsEnvironment(fakeEnv::get);
assertThat(reader.whatOs()).isEqualTo("MacDowsNix");

然而,这些环境变量的替代方案可能看起来很繁重,让我们希望 Java 能够像早期的 JavaScript 示例那样提供控制权。 同样,我们无法控制其他人编写的代码,这些代码可能依赖于环境变量。

因此,似乎不可避免的是,我们仍然可能会遇到想要能够在测试时动态控制某些环境变量的情况。

7. 结论

在本文中,我们研究了在测试时设置环境变量的选项。我们看到,当我们需要在运行时使这些变量灵活,并且可用于 JDK 17 及更高版本时,这样做会变得更加困难。

然后,我们讨论了如果我们以不同的方式编写生产代码,是否可以完全避免这个问题。我们考虑了在测试时修改环境变量相关的风险,尤其是在使用并发测试时。

我们还探讨了在测试时设置环境变量的四种最流行的库:JUnit Pioneer、System Stubs、System Rules 和 System Lambda。这些库中的每一个都提供了解决问题的不同方法,并且在 JDK 版本和测试框架之间具有不同的兼容性。

支持本文的代码可在 GitHub 上获取。 一旦你Baeldung Pro 会员 身份登录,就开始学习并在项目上进行编码。

 

Baeldung Pro – NPI EA (类别 = Baeldung)
announcement - icon

Baeldung Pro 具有完全无广告以及最终具有深色模式,提供干净的学习体验

>> 探索干净的 Baeldung

一旦早期采用者的席位全部用完,价格将上涨并保持在每年 33 美元。

电子书 – HTTP 客户端 – NPI EA (类别=HTTP 客户端)
announcement - icon

Apache HTTP Client 是一个非常强大的库,适用于简单和高级用例,在测试 HTTP 端点时尤其适用。 查看我们的指南,涵盖基本请求和响应处理,以及安全性、Cookie、超时等。

>> 下载电子书

电子书 – Java 并发 – NPI EA (分类=Java 并发)
announcement - icon

在应用程序中处理并发可能是一个棘手的过程,其中包含许多 潜在的陷阱。 扎实的掌握基本知识将有助于最大程度地减少这些问题。

通过我们的 Java 并发 指南开始了解多线程应用程序

>> 下载电子书

电子书 – Java Streams – NPI EA (分类=Java Streams)
announcement - icon

自从 Java 8 引入以来,Stream API 已成为 Java 开发的基础。 基本操作,例如迭代、过滤、映射元素序列,使用起来看似很简单。

但这些也可能被过度使用并陷入一些常见陷阱。

更好地了解 Stream 的工作方式 以及如何将其与其他语言功能结合使用,请查看我们关于 Java Streams 的指南

>> 加入 Pro 并下载电子书

电子书 – 持久化 – NPI EA (分类=持久化)
announcement - icon

您在努力实现正确的持久化层 Spring 吗?

探索电子书

课程 – LS – NPI EA (类别=REST)

announcement - icon

从 Spring Boot 开始,通过 Learn Spring 课程了解核心 Spring。

>> 查看课程

合作伙伴 – Moderne – NPI EA (标签=重构)
announcement - icon

现代 Java 团队行动迅速——但代码库并不总是跟上。 框架会发生变化,依赖关系会漂移,技术债务会累积,直到它开始拖慢交付速度。 OpenRewrite 就是为此而构建的:一个开源重构引擎,可在保持开发人员意图不变的同时自动化重复的代码更改。

由 Moderne 的 OpenRewrite 创建者和维护者领导的每月培训系列,将介绍实际的迁移和现代化模式。 无论您是重构配方的新手,还是准备编写自己的配方,您都将学习以安全且可扩展的方式进行重构的实用方法。

如果您曾经希望重构感觉像编写代码一样自然——并且一样快速——这是一个很好的起点

电子书 Jackson – NPI EA – 3 (类别 = Jackson)
© .