1

I'm experimenting with Netflix OSS for implementing a microservice architecture. I wanted to log server.port from bootstrap.yml file at runtime to see which instance is serving the request.

I'm using Java8.

Important libraries versions are:
* spring-boot-starter-web-1.5.8
* spring-boot-starter-tomcat-1.5.8
* tomcat-embed-core-8.5.23

After browsing on stackoverflow, I found this and this but these solution did not work.

My bootstrap.yml looks like this:

spring:
  application:
    name: some-service

server:
  port: ${port:8088}

I have tried following code:

@SpringBootApplication
@EnableEurekaClient
@SuppressWarnings("javadoc")
public class SomeService {

    private static Logger logger  = LoggerFactory.getLogger(SomeService .class);

    @LocalServerPort
    private static int randomServerPort;

    @LocalManagementPort
    private static int randomManagementPort;

    @Autowired
    private static Environment environment;

    @Value("${server.port}")
    // @Value("${local.server.port}")
    private static int port;

    public static void main(String[] args) {
        SpringApplication.run(SomeService .class, args);

        logger.info("randomServerPort : {}", randomServerPort);
        logger.info("randomManagementPort : {}", randomManagementPort);
        logger.info("server.port : {}", port);
        logger.info("environment.getProperty(\"server.port\") : {}", environment.getProperty("server.port"));

}

Corresponding output is:

randomServerPort : 0
randomManagementPort : 0
server.port : 0
java.lang.NullPointerException against environment.getProperty("server.port")

First three log statements log 0, while last one throws a `NullPointerException*.

At runtime, the port gets printed in logs on console as:

s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat initialized with port(s): 8088 (http)

I want to access this port number in main method of SomeService class. How can I do this?

narendra-choudhary
  • 4,582
  • 4
  • 38
  • 58

4 Answers4

2

You are attempting to access context information before Spring has created the context. Remove the static references, and access the data from a @PostConstruct block instead of main:

@Autowired
private Environment environment;

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

public static void main(String[] args) {
    SpringApplication.run(SomeService .class, args);
}

@PostConstruct
public void init() {
    logger.info("server.port : {}", port);
    logger.info("environment.getProperty(\"server.port\") : {}", environment.getProperty("server.port"));
}
Ian Mc
  • 5,656
  • 4
  • 18
  • 25
2

Static fields are not injected in Spring.
What you need to do is making it an instance field first.
Then you have to use it only after that the Spring Boot container has initialized it.
Moving them in a method annotated with @PostConstruct should do the job as this is invoked after that the dependency injection was performed.

@SpringBootApplication
@EnableEurekaClient
@SuppressWarnings("javadoc")
public class SomeService {

    private static Logger logger  = LoggerFactory.getLogger(SomeService .class);

    @LocalServerPort
    private static int randomServerPort;

    @LocalManagementPort
    private static int randomManagementPort;

    @Autowired
    private static Environment environment;

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

    @PostConstruct
    public void postConstruct(){
        logger.info("randomServerPort : {}", randomServerPort);
        logger.info("randomManagementPort : {}", randomManagementPort);
        logger.info("server.port : {}", port);
        logger.info("environment.getProperty(\"server.port\") : {}", environment.getProperty("server.port"));
    }    

    public static void main(String[] args) {
        SpringApplication.run(SomeService .class, args);
    }

}
davidxxx
  • 125,838
  • 23
  • 214
  • 215
0

Move your server port configuration from bootstrap.yml to application.yml

application.yml

server:
  port: 8088

Typically bootstrap.yml contains two properties: location of the configuration server (spring.cloud.config.uri) and name of the application (spring.application.name). Upon startup, Spring Cloud makes an HTTP call to the config server with the name of the application and retrieves back that application's configuration. On the other hand, application.yml contains standard application configurations - typically default configuration since any configuration retrieved during the bootstrap process will override configurations defined here.

Monzurul Shimul
  • 8,132
  • 2
  • 28
  • 42
  • I earlier had `server.port` in *application.yml* only. But I was facing the same issue as mentioned in question above. Since *bootstrap.yml* is loaded before *application.yml*, I thought moving `server.port` to *bootstrap.yml* might resolve the issue. But it did not help. I'll move `server.port` back to *application.yml*. – narendra-choudhary Mar 01 '18 at 20:52
0

I had the same issue and found out this solution to get the server.port value set in my application.properties file :

@SpringBootApplication
public class MyApp {

    private static final Logger LOG = LogManager.getLogger();

        public static void main(String[] args) {
            var app = new SpringApplication(MyApp .class);
            app.setLogStartupInfo(false);
            String serverPort = app.run(args).getEnvironment().getProperty("server.port");
            LOG.info("=== Server is up on port {} ===", serverPort);
        }
    }

I'm a bit late but I hope this helps :)

BenSev
  • 1
  • 2