1. 概述
Spring Boot 應用嵌入了一個 Web 服務器,有時我們可能需要動態地發現 HTTP 端口。
在本教程中,我們將學習如何在 Spring Boot 應用中通過編程方式獲取 HTTP 端口。
2. 簡介
本指南將介紹...
2.1. 我們的 Spring Boot 應用程序
我們將創建一個簡單的 Spring Boot 應用程序示例,以快速演示如何在運行時發現 HTTP 端口的方法:
@SpringBootApplication
public class GetServerPortApplication {
public static void main(String[] args) {
SpringApplication.run(GetServerPortApplication.class, args);
}
}
2.2. 設置端口的兩種場景
通常,配置 Spring Boot 應用程序的 HTTP 端口最直接的方法是定義端口在配置文件中,例如 application.properties 或 application.yml 中。
例如,在 application.properties 文件中,我們可以將應用程序運行的端口設置為 7777。
server.port=7777
當然,以下是翻譯後的內容:
或者,與其定義一個固定的端口,我們可以讓 Spring Boot 應用在隨機端口上運行,通過將 "0" 設置為 "server.port" 屬性的值來實現:
server.port=0
接下來,我們來探討兩個場景並討論如何通過編程方式在運行時獲取端口。
在本教程中,我們將通過單元測試發現服務器端口。
3. 運行時固定端口
讓我們創建一個名為 application-fixedport.properties 的屬性文件,並在其中定義一個固定的端口 7777:
server.port=7777接下來,我們將嘗試在一個單元測試類中獲取端口:
@RunWith(SpringRunner.class)
@SpringBootTest(classes = GetServerPortApplication.class,
webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
@ActiveProfiles("fixedport")
public class GetServerFixedPortUnitTest {
private final static int EXPECTED_PORT = 7777;
....
}
在查看測試方法之前,我們先快速瞭解一下測試類的註解:
- @RunWith(SpringRunner.class) – 這將 JUnit 測試與 Spring 的 TestContext 結合
- @SpringBootTest( … SpringBootTest.WebEnvironment.DEFINED_PORT) – 在 SpringBootTest 中,我們使用 DEFINED_PORT 來啓動嵌入式 Web 服務器
- @ActiveProfiles(“fixedport”) – 通過此註解,我們啓用了 Spring 配置文件 “fixedport”
3.1. 使用 <em @Value(“${server.port}”) 註解
由於 <em application-fixedport.properties 文件將被加載,我們可以使用 <em @Value 註解獲取 “<em server.port” 屬性:
@Value("${server.port}")
private int serverPort;
@Test
public void givenFixedPortAsServerPort_whenReadServerPort_thenGetThePort() {
assertEquals(EXPECTED_PORT, serverPort);
}
3.2. 使用 ServerProperties 類
ServerProperties 包含嵌入式 Web 服務器的屬性,例如端口、地址和服務器頭信息。
我們可以注入 ServerProperties 組件並從中獲取端口:
@Autowired
private ServerProperties serverProperties;
@Test
public void givenFixedPortAsServerPort_whenReadServerProps_thenGetThePort() {
int port = serverProperties.getPort();
assertEquals(EXPECTED_PORT, port);
}據目前為止,我們已經學習了兩種在運行時獲取固定端口的方法。接下來,讓我們看看如何在隨機端口場景中發現端口。
4. 運行時獲取隨機端口
現在,讓我們創建一個新的屬性文件 application-randomport.properties:
server.port=0如上代碼所示,我們允許 Spring Boot 在 Web 服務器啓動時隨機選擇一個空閒端口。
同樣地,讓我們創建一個新的單元測試類:
....
@ActiveProfiles("randomport")
public class GetServerRandomPortUnitTest {
...
}
這裏,我們需要激活“randomport” Spring 配置文件,以加載相應的屬性文件。
我們已經學習了兩種在運行時發現固定端口的方法。但是,它們無法幫助我們獲取隨機端口:
@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);
}
正如這兩個測試方法所示,both @Value(“${server.port}”) 和 serverProperties.getPort() 都報告端口為“0”。 顯然,這並不是我們期望的端口。
4.1. 使用 ServletWebServerApplicationContext
Spring Boot 在嵌入式 Web 服務器啓動時,會啓動一個 ServletWebServerApplicationContext。
因此,我們可以從上下文對象中獲取 WebServer,從而獲取服務器信息或操作服務器:
@Autowired
private ServletWebServerApplicationContext webServerAppCtxt;
@Test
public void given0AsServerPort_whenReadWebAppCtxt_thenGetThePort() {
int port = webServerAppCtxt.getWebServer().getPort();
assertTrue(port > 1023);
}
在上述測試中,我們檢查端口是否大於 1023。這是因為 0-1023 是系統端口。
4.2. 處理 ServletWebServerInitializedEvent 事件
Spring 應用可以發佈各種事件,並且 事件監聽器 處理這些事件。
當嵌入式 Web 服務器啓動時,將會發佈一個 ServletWebServerInitializedEvent 事件。該事件包含有關 Web 服務器的信息。
因此,我們可以創建一個 事件監聽器 以從該事件中獲取端口號:
@Service
public class ServerPortService {
private int port;
public int getPort() {
return port;
}
@EventListener
public void onApplicationEvent(final ServletWebServerInitializedEvent event) {
port = event.getWebServer().getPort();
}
}我們可以將服務組件注入到測試類中,以便快速獲取隨機端口:
@Autowired
private ServerPortService serverPortService;
@Test
public void given0AsServerPort_whenReadFromListener_thenGetThePort() {
int port = serverPortService.getPort();
assertTrue(port > 1023);
}
5. 結論
通常,我們會在屬性文件或 YAML 文件中配置 Spring Boot 應用程序的服務器端口,其中我們可以設置固定端口或隨機端口。
在本文中,我們討論了在運行時獲取固定端口和隨機端口的不同方法。