Spring Boot - How to get the running port

129,766

Solution 1

Thanks to @Dirk Lachowski for pointing me in the right direction. The solution isn't as elegant as I would have liked, but I got it working. Reading the spring docs, I can listen on the EmbeddedServletContainerInitializedEvent and get the port once the server is up and running. Here's what it looks like -

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();
      }
    }

Solution 2

Is it also possible to access the management port in a similar way, e.g.:

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

    @LocalServerPort
    int randomServerPort;

    @LocalManagementPort
    int randomManagementPort;

Solution 3

Spring's Environment holds this information for you.

@Autowired
Environment environment;

String port = environment.getProperty("local.server.port");

On the surface this looks identical to injecting a field annotated @Value("${local.server.port}") (or @LocalServerPort, which is identical), whereby an autowiring failure is thrown at startup as the value isn't available until the context is fully initialised. The difference here is that this call is implicitly being made in runtime business logic rather than invoked at application startup, and hence the 'lazy-fetch' of the port resolves ok.

Solution 4

You can get the port that is being used by an embedded Tomcat instance during tests by injecting the local.server.port value as such:

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

Solution 5

Just so others who have configured their apps like mine benefit from what I went through...

None of the above solutions worked for me because I have a ./config directory just under my project base with 2 files:

application.properties
application-dev.properties

In application.properties I have:

spring.profiles.active = dev  # set my default profile to 'dev'

In application-dev.properties I have:

server_host = localhost
server_port = 8080

This is so when I run my fat jar from the CLI the *.properties files will be read from the ./config dir and all is good.

Well, it turns out that these properties files completely override the webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT setting in @SpringBootTest in my Spock specs. No matter what I tried, even with webEnvironment set to RANDOM_PORT Spring would always startup the embedded Tomcat container on port 8080 (or whatever value I'd set in my ./config/*.properties files).

The ONLY way I was able to overcome this was by adding an explicit properties = "server_port=0" to the @SpringBootTest annotation in my Spock integration specs:

@SpringBootTest (webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, properties = "server_port=0")

Then, and only then did Spring finally start to spin up Tomcat on a random port. IMHO this is a Spring testing framework bug, but I'm sure they'll have their own opinion on this.

Hope this helped someone.

Share:
129,766

Related videos on Youtube

Tucker
Author by

Tucker

upvote

Updated on July 08, 2022

Comments

  • Tucker
    Tucker almost 2 years

    I have a spring boot application (using embedded tomcat 7), and I've set server.port = 0 in my application.properties so I can have a random port. After the server is booted up and running on a port, I need to be able to get the port that that was chosen.

    I cannot use @Value("$server.port") because it's zero. This is a seemingly simple piece of information, so why can't I access it from my java code? How can I access it?

  • ejain
    ejain over 8 years
    local.server.port is only set when running with @WebIntegrationTests
  • mre
    mre about 8 years
    AFAIK this won't work if you're looking to configure a bean with the server port. This event isn't fired off until after all the beans have been loaded and the servlets have been registered.
  • Tucker
    Tucker about 8 years
    it worked for me at the time thats why I accepted it. I haven't tried hennr's answer though.
  • Matthew Wise
    Matthew Wise over 7 years
    After reading the docs I came up with virtually the same small class as you, naming it PortProvider, and providing a getPort() method. Autowired my PortProvider in to the controller needing the port, and when my business logic called portProvider.getPort(), the runtime port was returned.
  • NiteLite
    NiteLite about 7 years
    For anyone trying this with Spring Boot 2.0 or later, the API seems to have changed slightly. I was no longer able to subscribe to EmbeddedServletContainerInitializedEvent, but there is a similar class called ServletWebServerInitializedEvent which has a .getWebServer() method. This will get you the port Tomcat is listening to at least.
  • bvulaj
    bvulaj about 6 years
    Have this exact same setup and also ran into this. I assumed this was the issue in some sense, but thanks for posting your solution here. Do you know if anyone has logged this as a bug yet?
  • Jeef
    Jeef about 6 years
    I wanted the same thing for swagger
  • deamon
    deamon over 5 years
    @LocalServerPort is just a shortcut for @Value("${local.server.port}").
  • Anand Rockzz
    Anand Rockzz over 5 years
    for some reason this didnt work for me, environment.getProperty("server.port") did.
  • Ahmed
    Ahmed about 4 years
    I have made changes to my answer are you still having the same issue?
  • chill appreciator
    chill appreciator over 3 years
    @deamon means if you not specify local.server.port in properties - it wont works
  • Ken Pronovici
    Ken Pronovici over 3 years
    This is the right answer for Spring Boot 2. Works fine with @SpringBootTest and WebEnvironment.RANDOM_PORT.
  • kyakya
    kyakya over 3 years
    WebIntegrationTest is Deprecated.
  • Muhammad Muzammil
    Muhammad Muzammil over 3 years
    Using webEnvironment = WebEnvironment.RANDOM_PORT resolved the issue. Thanks
  • Dirk Schumacher
    Dirk Schumacher almost 3 years
    I think that's a bad idea. The information can be retrieved when a request ist made. Probably one wants to know the port on startup before the first request is made.
  • Dirk Schumacher
    Dirk Schumacher almost 3 years
    Another issue which could be severe if wrongly adapted is that the HttpServletRequest is set as a private member variable of a controller class. When having two request at the 'same' time the setting of 'request' will be overwritten since the class is a singleton (isn't it? - let me know) If it was thread-wise the implementation would be ok. (also see: stackoverflow.com/a/4506382/845117)