Spring Boot - 如何获取正在运行的端口

Tuc*_*ker 62 port spring embedded-tomcat-7 spring-boot

我有一个spring boot应用程序(使用嵌入式tomcat 7),我已经设置server.port = 0了我的application.properties所以我可以有一个随机端口.服务器启动并在端口上运行后,我需要能够获得所选的端口.

我不能使用,@Value("$server.port")因为它是零.这是一个看似简单的信息,为什么我不能从我的java代码中访问它?我该如何访问它?

小智 73

是否也可以以类似的方式访问管理端口,例如:

  @SpringBootTest(classes = {Application.class}, webEnvironment = WebEnvironment.RANDOM_PORT)
  public class MyTest {

    @LocalServerPort
    int randomServerPort;

    @LocalManagementPort
    int randomManagementPort;
Run Code Online (Sandbox Code Playgroud)

  • [`@ LocalServerPort`](https://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/web/server/LocalServerPort.html)只是@Value( “ $ {local.server.port}”)`。 (4认同)
  • 使用“webEnvironment = WebEnvironment.RANDOM_PORT”解决了该问题。谢谢 (2认同)

hen*_*nnr 58

Spring的环境为您提供此信息.

@Autowired
Environment environment;

String port = environment.getProperty("local.server.port");
Run Code Online (Sandbox Code Playgroud)

从表面上看,这看起来与注入注释的字段@Value("${local.server.port}")(或@LocalServerPort相同的)相同,从而在启动时抛出自动装配失败,因为在完全初始化上下文之前该值不可用.这里的区别在于,此调用隐式在运行时业务逻辑中进行,而不是在应用程序启动时调用,因此端口的"lazy-fetch"可以解决.

  • 由于某种原因,这对我不起作用,`environment.getProperty(“ server.port”)`起作用了。 (3认同)

Tuc*_*ker 21

感谢@Dirk Lachowski将我指向了正确的方向.解决方案并不像我希望的那样优雅,但我得到了它的工作.阅读spring docs,我可以监听EmbeddedServletContainerInitializedEvent并在服务器启动并运行后获取端口.这是它的样子 -

import org.springframework.boot.context.embedded.EmbeddedServletContainerInitializedEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;




    @Component
    public class MyListener implements ApplicationListener<EmbeddedServletContainerInitializedEvent> {

      @Override
      public void onApplicationEvent(final EmbeddedServletContainerInitializedEvent event) {
          int thePort = event.getEmbeddedServletContainer().getPort();
      }
    }
Run Code Online (Sandbox Code Playgroud)

  • 对于使用Spring Boot 2.0或更高版本进行此操作的任何人来说,API似乎都略有改变.我不再能够订阅`EmbeddedServletContainerInitializedEvent`,但是有一个名为`ServletWebServerInitializedEvent`的类,它有一个`.getWebServer()`方法.这将使您获得Tomcat至少正在收听的端口. (7认同)

Jac*_*man 13

就像其他配置了我的应用程序的人一样受益于我所经历的......

上述解决方案中没有工作对我来说,因为我有一个./config目录不到我的项目基地,2个文件:

application.properties
application-dev.properties

application.properties我有:

spring.profiles.active = dev  # set my default profile to 'dev'
Run Code Online (Sandbox Code Playgroud)

application-dev.properties我有:

server_host = localhost
server_port = 8080
Run Code Online (Sandbox Code Playgroud)

这是当我从CLI运行我的胖罐时,*.properties文件将从./config目录中读取,一切都很好.

好吧,事实证明这些属性文件完全覆盖了我的Spock规范中的webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT设置 @SpringBootTest.无论我尝试什么,即使webEnvironment设置为RANDOM_PORTSpring,也总是在端口8080上启动嵌入式Tomcat容器(或者我在./config/*.properties文件中设置的任何值).

我能够克服这个问题的唯一方法是在我的Spock集成规范中添加一个明确properties = "server_port=0"@SpringBootTest注释:

@SpringBootTest (webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, properties = "server_port=0")
Run Code Online (Sandbox Code Playgroud)

然后,只有这样,Spring终于开始在随机端口上启动Tomcat.恕我直言这是一个Spring测试框架错误,但我相信他们对此有自己的看法.

希望这有助于某人.


bsy*_*syk 12

您可以通过注入local.server.port值来获取测试期间嵌入式Tomcat实例正在使用的端口:

// Inject which port we were assigned
@Value("${local.server.port}")
int port;
Run Code Online (Sandbox Code Playgroud)

  • `local.server.port`仅在使用`@WebIntegrationTests`运行时设置 (12认同)

jab*_*bal 12

从Spring Boot 1.4.0开始,您可以在测试中使用它:

import org.springframework.boot.context.embedded.LocalServerPort;

@SpringBootTest(classes = {Application.class}, webEnvironment = WebEnvironment.RANDOM_PORT)
public class MyTest {

  @LocalServerPort
  int randomPort;

  // ...
}
Run Code Online (Sandbox Code Playgroud)


Sam*_*Sam 7

在 Spring Boot 2 之后,发生了很多变化。上面给出的答案在 Spring Boot 2 之前有效。现在,如果您使用服务器端口的运行时参数运行您的应用程序,那么您将只能获得application.properties文件中@Value("${server.port}")提到的静态值。现在要获取服务器运行的实际端口,请使用以下方法:

    @Autowired
    private ServletWebServerApplicationContext server;

    @GetMapping("/server-port")
    public String serverPort() {

        return "" + server.getWebServer().getPort();
    }
Run Code Online (Sandbox Code Playgroud)

此外,如果您将应用程序用作负载平衡的 Eureka/Discovery 客户端RestTemplateWebClient,上述方法将返回确切的端口号。

  • 这是 Spring Boot 2 的正确答案。与 @SpringBootTest 和 WebEnvironment.RANDOM_PORT 配合良好。 (2认同)

mre*_*mre 6

这些解决方案都不适合我.构建Swagger配置bean时,我需要知道服务器端口.使用ServerProperties为我工作:

import javax.annotation.PostConstruct;
import javax.inject.Inject;
import javax.ws.rs.ApplicationPath;

import io.swagger.jaxrs.config.BeanConfig;
import io.swagger.jaxrs.listing.ApiListingResource;
import io.swagger.jaxrs.listing.SwaggerSerializers;

import org.glassfish.jersey.server.ResourceConfig;
import org.springframework.stereotype.Component;

@Component
@ApplicationPath("api")
public class JerseyConfig extends ResourceConfig 
{
    @Inject
    private org.springframework.boot.autoconfigure.web.ServerProperties serverProperties;

    public JerseyConfig() 
    {
        property(org.glassfish.jersey.server.ServerProperties.BV_SEND_ERROR_IN_RESPONSE, true);
    }

    @PostConstruct
    protected void postConstruct()
    {
        // register application endpoints
        registerAndConfigureSwaggerUi();
    }

    private void registerAndConfigureSwaggerUi()
    {
        register(ApiListingResource.class);
        register(SwaggerSerializers.class);

        final BeanConfig config = new BeanConfig();
        // set other properties
        config.setHost("localhost:" + serverProperties.getPort()); // gets server.port from application.properties file         
    }
}
Run Code Online (Sandbox Code Playgroud)

此示例使用Spring Boot自动配置和JAX-RS(不是Spring MVC).