Get the Running Port in Spring Boot – 获取Spring Boot中的运行端口

最后修改: 2020年 9月 28日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

A Spring Boot application embeds a web server, and sometimes, we may want to discover the HTTP port at runtime.

一个Spring Boot应用程序嵌入了一个Web服务器,有时,我们可能想在运行时发现HTTP端口。

In this tutorial, we’ll address how to get the HTTP port programmatically in a Spring Boot application.

在本教程中,我们将讨论如何在Spring Boot应用程序中以编程方式获取HTTP端口。

2. Introduction

2.绪论

2.1. Our Spring Boot Application

2.1.我们的Spring Boot应用

We’ll create a simple Spring Boot application example to quickly show the methods to discover the HTTP port at runtime:

我们将创建一个简单的Spring Boot应用实例,快速展示在运行时发现HTTP端口的方法。

@SpringBootApplication
public class GetServerPortApplication {
    public static void main(String[] args) {
        SpringApplication.run(GetServerPortApplication.class, args);
    }
}

2.2. Two Scenarios of Setting the Port

2.2.设置端口的两种情况

Usually, the most straightforward way to configure the HTTP port of a Spring Boot application is by defining the port in the configuration file application.properties or application.yml.

通常,配置Spring Boot应用程序的HTTP端口的最直接方式是在配置文件application.propertiesapplication.yml中定义该端口。

For example, in the application.properties file, we can set 7777 as the port our application is running on:

例如,在application.properties文件中,我们可以设置7777作为我们的应用程序运行的端口。

server.port=7777

Alternatively, instead of defining a fixed port, we can let the Spring Boot application run on a random port by setting “0” as the value of the “server.port” property:

另外,我们可以通过设置”0“作为”server.port“属性的值,让Spring Boot应用程序在随机端口上运行,而不是定义一个固定的端口。

server.port=0

Next, let’s go through the two scenarios and discuss different ways to get the port programmatically at runtime.

接下来,让我们通过这两种情况,讨论在运行时以编程方式获取端口的不同方法。

In this tutorial, we’ll discover the server port in unit tests.

在本教程中,我们将发现单元测试中的服务器端口。

3. Getting a Fixed Port at Runtime

3.在运行时获得一个固定的端口

Let’s create a properties file application-fixedport.properties and define a fixed port 7777 in it:

让我们创建一个属性文件application-fixedport.properties并在其中定义一个固定端口7777

server.port=7777

Next, we’ll try to get the port in a unit test class:

接下来,我们将尝试在一个单元测试类中获得端口。

@RunWith(SpringRunner.class)
@SpringBootTest(classes = GetServerPortApplication.class,
  webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
@ActiveProfiles("fixedport")
public class GetServerFixedPortUnitTest {
    private final static int EXPECTED_PORT = 7777;
    ....
}

Before we see the test methods, let’s take a quick look at the annotations of the test class:

在我们看到测试方法之前,让我们快速看一下测试类的注释。

  • @RunWith(SpringRunner.class) – This will join the JUnit test with the Spring TestContext
  • @SpringBootTest( … SpringBootTest.WebEnvironment.DEFINED_PORT) – In the SpringBootTest, we’ll use the DEFINED_PORT for the embedded web server
  • @ActiveProfiles(“fixedport”) – With this annotation, we enabled the Spring profilefixedport” so that our application-fixedport.properties will be loaded

3.1. Using the @Value(“${server.port}”) Annotation

3.1.使用@Value(“${server.port}”)/em>注解

Since the application-fixedport.properties file will be loaded, we can get the “server.port” property using the @Value annotation:

由于application-fixedport.properties文件将被加载,我们可以使用@Value注解来获得”server.port“属性。

@Value("${server.port}")
private int serverPort;

@Test
public void givenFixedPortAsServerPort_whenReadServerPort_thenGetThePort() {
    assertEquals(EXPECTED_PORT, serverPort);
}

3.2. Using the ServerProperties Class

3.2.使用ServerProperties

ServerProperties holds the properties of the embedded web server, such as the port, the address, and the server header.

ServerProperties持有嵌入式Web服务器的属性,如端口、地址和服务器头。

We can inject a ServerProperties component and get the port from it:

我们可以注入一个ServerProperties组件并从中获取端口。

@Autowired
private ServerProperties serverProperties;

@Test
public void givenFixedPortAsServerPort_whenReadServerProps_thenGetThePort() {
    int port = serverProperties.getPort();
 
    assertEquals(EXPECTED_PORT, port);
}

So far, we’ve learned two ways to get a fixed port at runtime. Next, let’s see how to discover the port in the random port scenario.

到目前为止,我们已经学会了两种在运行时获得固定端口的方法。接下来,让我们看看如何在随机端口的情况下发现端口。

4. Getting Random Port at Runtime

4.在运行时获得随机端口

This time, let’s create another properties file application-randomport.properties:

这一次,让我们创建另一个属性文件application-randomport.properties

server.port=0

As the code above shows, we allow Spring Boot to choose a free port randomly when the web server starts.

如上面的代码所示,我们允许Spring Boot在Web服务器启动时随机选择一个空闲端口。

In the same vein, let’s create another unit test class:

同样地,让我们再创建一个单元测试类。

....
@ActiveProfiles("randomport")
public class GetServerRandomPortUnitTest {
...
}

Here, we need to activate the “randomport” Spring profile to load the corresponding properties file.

在这里,我们需要激活”randomport“Spring配置文件以加载相应的属性文件。

We’ve learned two ways to discover a fixed port at runtime. However, they can’t help us to get the random port:

我们已经学会了两种在运行时发现固定端口的方法。然而,它们不能帮助我们获得随机的端口。

@Value("${server.port}")
private int randomServerPort;

@Test
public void given0AsServerPort_whenReadServerPort_thenGet0() {
    assertEquals(0, randomServerPort);
}

@Autowired
private ServerProperties serverProperties;

@Test
public void given0AsServerPort_whenReadServerProps_thenGet0() {
    int port = serverProperties.getPort();
 
    assertEquals(0, port);
}

As the two test methods show, both @Value(“${server.port}”) and serverProperties.getPort() report “0” as the port. Clearly, it is not the correct port we are expecting.

正如两个测试方法所显示的,@Value(“${server.port}”)serverProperties.getPort()都报告 “0 “为端口。显然,这不是我们所期望的正确端口。

4.1. Using ServletWebServerApplicationContext

4.1.使用ServletWebServerApplicationContext

Spring Boot starts a ServletWebServerApplicationContext if the embedded web server starts.

如果嵌入式Web服务器启动,Spring Boot会启动一个ServletWebServerApplicationContext

Therefore, we can get the WebServer from the context object to obtain the server information or manipulate the server:

因此,我们可以从上下文对象中获得WebServer以获得服务器信息或操纵服务器。

@Autowired
private ServletWebServerApplicationContext webServerAppCtxt;

@Test
public void given0AsServerPort_whenReadWebAppCtxt_thenGetThePort() {
    int port = webServerAppCtxt.getWebServer().getPort();
 
    assertTrue(port > 1023);
}

In the test above, we check if the port is greater than 1023. This is because 0-1023 are system ports.

在上面的测试中,我们检查端口是否大于1023。这是因为0-1023是系统端口。

4.2. Handling ServletWebServerInitializedEvent

4.2.处理ServletWebServerInitializedEvent

A Spring application can publish various events and EventListeners handle the events.

Spring应用程序可以发布各种事件,并且EventListeners处理事件。

When the embedded web server has started, a ServletWebServerInitializedEvent will be published. This event contains information about the webserver.

当嵌入式Web服务器启动后,将发布一个ServletWebServerInitializedEvent。该事件包含有关Web服务器的信息。

Therefore, we can create an EventListener to get the port from this event:

因此,我们可以创建一个EventListener来从这个事件中获取端口。

@Service
public class ServerPortService {
    private int port;

    public int getPort() {
        return port;
    }

    @EventListener
    public void onApplicationEvent(final ServletWebServerInitializedEvent event) {
        port = event.getWebServer().getPort();
    }
}

We can inject the service component to our test class to get the random port quickly:

我们可以将服务组件注入到我们的测试类中,以快速获得随机端口。

@Autowired
private ServerPortService serverPortService;

@Test
public void given0AsServerPort_whenReadFromListener_thenGetThePort() {
    int port = serverPortService.getPort();
 
    assertTrue(port > 1023);
}

5. Conclusion

5.总结

Usually, we configure the server port of a Spring Boot application in a properties file or YAML file, where we can set either a fixed or random port.

通常,我们在属性文件或YAML文件中配置Spring Boot应用程序的服务器端口,在这里我们可以设置一个固定的或随机的端口。

In this article, we’ve discussed different approaches to obtain the fixed and random port at runtime.

在这篇文章中,我们已经讨论了在运行时获得固定和随机端口的不同方法。

As always, the full source code of the article is available over on GitHub.

一如既往,该文章的完整源代码可在GitHub上获得