32

I'm starting up a Spring Boot application with mvn spring-boot:run.

One of my @Controllers needs information about the host and port the application is listening on, i.e. localhost:8080 (or 127.x.y.z:8080). Following the Spring Boot documentation, I use the server.address and server.port properties:

@Controller
public class MyController {

    @Value("${server.address}")
    private String serverAddress;

    @Value("${server.port}")
    private String serverPort;

    //...

}

When starting up the application with mvn spring-boot:run, I get the following exception:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'myController': Injection of autowired dependencies failed; nested exception is 
org.springframework.beans.factory.BeanCreationException: Could not autowire field: ... String ... serverAddress; nested exception is java.lang.IllegalArgumentException: Could not resolve placeholder 'server.address' in string value "${server.address}"

Both server.address and server.port cannot be autowired.

How can I find out the (local) host/address/NIC and port that a Spring Boot application is binding on?

risingTide
  • 1,754
  • 7
  • 31
  • 60
Abdull
  • 26,371
  • 26
  • 130
  • 172
  • 1
    Have you declared them on `application.properties` ? – Joao Evangelista Apr 28 '15 at 22:45
  • Why would you need that? If you want to create a link for the user you can get the information from HttpServletRequest (can be put as parameter in controller methods) – derkoe Apr 29 '15 at 07:48
  • imo, `server.port` has a default and therefore will evaluate to something, but `server.address` do not have, so that might be a problem – sodik Apr 29 '15 at 08:02
  • 2
    It will only be available if explicitly set else it isn't available, when properties aren't set they aren't set on the underlying server (tomcat, jetty or undertow) automatically enabling the defaults of that container. To get the server address you can use the `InetAddress` class to get the local ip-address, for the port you can use `${server.port:8080}` is you are using tomcat (this trick would also work for the `server.address` of course. Just wondering why do you need this informaion, i.e what is your usecase. – M. Deinum Apr 29 '15 at 09:25
  • 1
    Pardon the add to an old comment, but one possible use case is that of an application integrating with Oozie REST. Oozie REST has a concept of a callback URL which is called by Oozie when an Oozie job is updated. If, for example, you had a web service interacting with Oozie and wanted job updates reactively, this information would be needed so Oozie REST could properly contact your REST service. In my case, I implemented said use case and used InetAddress like so: `def hostname(): String = InetAddress.getLocalHost.getHostName`. Oozie REST could then call my REST service to provide updates – medge Nov 09 '15 at 17:25
  • If you really care about these values then they should be specified in your properties file to avoid unexpected defaults. While you can accurately determine the port selected for listening you will find that on a multi-homed server you'll be listening on *all* available addresses unless you say otherwise in your properties file. – Andy Brown Jan 02 '19 at 09:52

10 Answers10

19

IP Address

You can get network interfaces with NetworkInterface.getNetworkInterfaces(), then the IP addresses off the NetworkInterface objects returned with .getInetAddresses(), then the string representation of those addresses with .getHostAddress().

Port

If you make a @Configuration class which implements ApplicationListener<EmbeddedServletContainerInitializedEvent>, you can override onApplicationEvent to get the port number once it's set.

@Override
public void onApplicationEvent(EmbeddedServletContainerInitializedEvent event) {
    int port = event.getEmbeddedServletContainer().getPort();
}
Kiwi
  • 1,083
  • 11
  • 26
  • How would you actually use this value within the application? I am struggling to find a way to make this value reliably accessible within other components. It seems like there is not way to ensure that the container is created before the beans are initialized that might want to use the port. – Seth M. Jan 04 '18 at 22:13
  • `EmbeddedServletContainerInitializedEvent` is no longer available in Spring Boot 2.x – n_l Oct 30 '18 at 11:32
  • 2
    It looks like it may have been renamed to/replaced by [WebServerInitializedEvent](https://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/web/context/WebServerInitializedEvent.html). See [the relevant portion](https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-2.0-Migration-Guide#embedded-containers-package-structure) of the migration guide. – Kiwi Oct 30 '18 at 17:10
15

You can get port info via

@Value("${local.server.port}")
private String serverPort;
azizunsal
  • 2,074
  • 1
  • 25
  • 33
8

An easy workaround, at least to get the running port, is to add the parameter javax.servlet.HttpServletRequest in the signature of one of the controller's methods. Once you have the HttpServletRequest instance is straightforward to get the baseUrl with this: request.getRequestURL().toString()

Have a look at this code:

@PostMapping(value = "/registration" , produces = "application/json")
public StringResponse register(@RequestBody RequestUserDTO userDTO, 
    HttpServletRequest request) {
request.getRequestURL().toString();
//value: http://localhost:8080/registration
------
return "";
}
Enrico Giurin
  • 2,183
  • 32
  • 30
7

I have just found a way to get server ip and port easily by using Eureka client library. As I am using it anyway for service registration, it is not an additional lib for me just for this purpose.

You need to add the maven dependency first:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    <version>2.2.2.RELEASE</version>
</dependency>

Then you can use the ApplicationInfoManager service in any of your Spring beans.

@Autowired
private ApplicationInfoManager applicationInfoManager;
...

InstanceInfo applicationInfo = applicationInfoManager.getInfo();

The InstanceInfo object contains all important information about your service, like IP address, port, hostname, etc.

eL_
  • 167
  • 2
  • 17
vargapeti
  • 301
  • 2
  • 7
6

One solution mentioned in a reply by @M. Deinum is one that I've used in a number of Akka apps:

object Localhost {

  /**
   * @return String for the local hostname
   */
  def hostname(): String = InetAddress.getLocalHost.getHostName

  /**
   * @return String for the host IP address
   */
  def ip(): String = InetAddress.getLocalHost.getHostAddress

}

I've used this method when building a callback URL for Oozie REST so that Oozie could callback to my REST service and it's worked like a charm

medge
  • 598
  • 5
  • 16
5

To get the port number in your code you can use the following:

@Autowired
Environment environment;

@GetMapping("/test")
String testConnection(){
    return "Your server is up and running at port: "+environment.getProperty("local.server.port");      
}

To understand the Environment property you can go through this Spring boot Environment

Sen
  • 1,308
  • 12
  • 12
3

You can get hostname from spring cloud property in spring-cloud-commons-2.1.0.RC2.jar

environment.getProperty("spring.cloud.client.ip-address");
environment.getProperty("spring.cloud.client.hostname");

spring.factories of spring-cloud-commons-2.1.0.RC2.jar

org.springframework.boot.env.EnvironmentPostProcessor=\
org.springframework.cloud.client.HostInfoEnvironmentPostProcessor
2

For Spring 2

val hostName = InetAddress.getLocalHost().hostName

var webServerPort: Int = 0
@Configuration
class ApplicationListenerWebServerInitialized : ApplicationListener<WebServerInitializedEvent> {
    override fun onApplicationEvent(event: WebServerInitializedEvent) {
        webServerPort = event.webServer.port
    }
}

then you can use also webServerPort from anywhere...

Renetik
  • 5,887
  • 1
  • 47
  • 66
-1

I used to declare the configuration in application.properties like this (you can use you own property file)

server.host = localhost
server.port = 8081

and in application you can get it easily by @Value("${server.host}") and @Value("${server.port}") as field level annotation.

or if in your case it is dynamic than you can get from system properties

Here is the example

@Value("#{systemproperties['server.host']}")
@Value("#{systemproperties['server.port']}")

For a better understanding of this annotation , see this example Multiple uses of @Value annotation

CuriousDev
  • 400
  • 3
  • 11
  • I believe application.properties inside resources folder from an Spring Boot application do not have property named server.host – Cuong Vo Aug 29 '22 at 15:09
-1
@Value("${hostname}")
private String hostname;

At Spring-boot 2.3, The hostname was add as the System Environment Property, and you can check it on /actuator/env

袁文涛
  • 735
  • 1
  • 10
  • 23