Spring Boot - How to get the running port
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.
Related videos on Youtube
Comments
-
Tucker almost 2 years
I have a spring boot application (using embedded tomcat 7), and I've set
server.port = 0
in myapplication.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?-
Dirk Lachowski almost 9 yearsRelated: stackoverflow.com/a/24643484/1686330
-
Dirk Lachowski almost 9 yearsAnother possibility can be found in the docs: docs.spring.io/spring-boot/docs/current/reference/html/… (see 64.5 Discover the HTTP port at runtime )
-
-
ejain over 8 years
local.server.port
is only set when running with@WebIntegrationTests
-
mre about 8 yearsAFAIK 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 about 8 yearsit worked for me at the time thats why I accepted it. I haven't tried hennr's answer though.
-
Matthew Wise over 7 yearsAfter reading the docs I came up with virtually the same small class as you, naming it
PortProvider
, and providing agetPort()
method. Autowired myPortProvider
in to the controller needing the port, and when my business logic calledportProvider.getPort()
, the runtime port was returned. -
NiteLite about 7 yearsFor 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 calledServletWebServerInitializedEvent
which has a.getWebServer()
method. This will get you the port Tomcat is listening to at least. -
bvulaj about 6 yearsHave 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 about 6 yearsI wanted the same thing for swagger
-
deamon over 5 years
@LocalServerPort
is just a shortcut for@Value("${local.server.port}")
. -
Anand Rockzz over 5 yearsfor some reason this didnt work for me,
environment.getProperty("server.port")
did. -
Ahmed about 4 yearsI have made changes to my answer are you still having the same issue?
-
chill appreciator over 3 years@deamon means if you not specify local.server.port in properties - it wont works
-
Ken Pronovici over 3 yearsThis is the right answer for Spring Boot 2. Works fine with @SpringBootTest and WebEnvironment.RANDOM_PORT.
-
kyakya over 3 yearsWebIntegrationTest is Deprecated.
-
Muhammad Muzammil over 3 yearsUsing
webEnvironment = WebEnvironment.RANDOM_PORT
resolved the issue. Thanks -
Dirk Schumacher almost 3 yearsI 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 almost 3 yearsAnother 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)