1、概览 {#1概览}
Spring Boot 应用嵌入了一个 Web 服务器,有时候我们可能希望在运行时获取 HTTP 端口。
本文将带你了解如何在 Spring Boot 应用中以编程式的方式获取 HTTP 端口。
2、示例 {#2示例}
2.1、Spring Boot 应用 {#21spring-boot-应用}
创建一个简单的 Spring Boot 应用示例,演示如何在运行时获取 HTTP 端口:
@SpringBootApplication
public class GetServerPortApplication {
public static void main(String[] args) {
SpringApplication.run(GetServerPortApplication.class, args);
}
}
2.2、设置端口号的两种方式 {#22设置端口号的两种方式}
通常,配置 Spring Boot 应用 HTTP 端口的最直接方法是在配置文件 application.properties
或 application.yml
中定义端口。
例如,在 application.properties
文件中,可以将 7777 设置为应用的运行端口:
server.port=7777
另外,也可以不定义固定端口,而是通过将 server.port
属性值设置为 0,让 Spring Boot 应用在随机端口上运行:
server.port=0
3、运行时获取固定端口 {#3运行时获取固定端口}
创建一个 properties 文件 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 Profile "fixedport",以便加载application-fixedport.properties
。
3.1、使用 @Value("${server.port}") 注解 {#31使用-valueserverport-注解}
由于会加载 application-fixedport.properties
文件,因此可以使用 @Value
注解获取 server.port
属性:
@Value("${server.port}")
private int serverPort;
@Test
public void givenFixedPortAsServerPort_whenReadServerPort_thenGetThePort() {
assertEquals(EXPECTED_PORT, serverPort);
}
3.2、使用 ServerProperties 类 {#32使用-serverproperties-类}
ServerProperties 包含嵌入式 Web 服务器的属性,如端口、地址和 Server Header。
可以注入 ServerProperties
组件并从中获取端口:
@Autowired
private ServerProperties serverProperties;
@Test
public void givenFixedPortAsServerPort_whenReadServerProps_thenGetThePort() {
int port = serverProperties.getPort();
assertEquals(EXPECTED_PORT, port);
}
4、运行时获取随机端口 {#4运行时获取随机端口}
创建另一个 properties 文件 application-randomport.properties
:
server.port=0
如上所示,允许 Spring Boot 在 Web 服务器启动时随机选择一个空闲端口。
同样,创建另一个单元测试类:
....
@ActiveProfiles("randomport")
public class GetServerRandomPortUnitTest {
...
}
如上,激活 "randomport" Spring Profile 来加载相应的 properties 文件。
上节所述的两种方式,都没法在运行时获取到随机端口:
@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);
}
正如两个测试方法所示,通过 @Value("${server.port}")
和 serverProperties.getPort()
获取到的端口都是 0。显然,这不是正确的运行时端口。
4.1、使用 ServletWebServerApplicationContext {#41使用-servletwebserverapplicationcontext}
如果嵌入式 Web 服务器启动,Spring Boot 就会启动 ServletWebServerApplicationContext
。
因此,可以从 context 对象中获取 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 事件 {#42servletwebserverinitializedevent-事件}
Spring 应用可以发布各种事件,而 EventListeners
可以处理这些事件。
嵌入式 Web 服务器启动后,将发布 ServletWebServerInitializedEvent
事件。该事件包含有关 Web 服务器的信息。
因此,可以创建一个 EventListener
来从该事件中获取端口:
@Service
public class ServerPortService {
private int port;
public int getPort() {
return port;
}
@EventListener
public void onApplicationEvent(final ServletWebServerInitializedEvent event) {
port = event.getWebServer().getPort();
}
}
将 ServerPortService
注入测试类,以快速获取随机端口:
@Autowired
private ServerPortService serverPortService;
@Test
public void given0AsServerPort_whenReadFromListener_thenGetThePort() {
int port = serverPortService.getPort();
assertTrue(port > 1023);
}
5、总结 {#5总结}
本文介绍了如何给 Spring Boot 应用设置固定端口和随机端口,以及如何在运行时获取到监听的端口信息。
Ref:https://www.baeldung.com/spring-boot-running-port