Spring Boot-실행중인 포트를 얻는 방법


89

스프링 부트 애플리케이션 (임베디드 tomcat 7 사용) 이 있으며 임의의 포트를 가질 수 있도록 설정 server.port = 0했습니다 application.properties. 서버가 부팅되고 포트에서 실행 된 후 선택한 포트를 가져올 수 있어야합니다.

@Value("$server.port")제로라서 사용할 수 없습니다 . 이것은 겉보기에 간단한 정보이므로 Java 코드에서 액세스 할 수없는 이유는 무엇입니까? 어떻게 액세스 할 수 있습니까?



또 다른 가능성은 다음 문서에서 찾을 수 있습니다 : docs.spring.io/spring-boot/docs/current/reference/html/… (64.5 런타임시 HTTP 포트 검색 참조)
Dirk Lachowski

답변:


95

다음과 같은 방법으로 관리 포트에 액세스 할 수도 있습니까?

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

    @LocalServerPort
    int randomServerPort;

    @LocalManagementPort
    int randomManagementPort;

6
@LocalServerPort의 바로 가기입니다 @Value("${local.server.port}").
deamon

당신이 속성 local.server.port 지정하지 않을 경우 수단 @deamon -이 작품 못해
자치

79

Spring의 환경은이 정보를 보유하고 있습니다.

@Autowired
Environment environment;

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

표면적으로 이것은 주석이 달린 @Value("${local.server.port}")(또는 @LocalServerPort동일한) 필드를 삽입하는 것과 동일 해 보이며 컨텍스트가 완전히 초기화 될 때까지 값을 사용할 수 없기 때문에 시작시 자동 연결 실패가 발생합니다. 여기서 차이점은이 호출이 응용 프로그램 시작시 호출되지 않고 런타임 비즈니스 논리에서 암시 적으로 수행되므로 포트의 '지연 가져 오기'가 정상적으로 해결된다는 것입니다.


4
어떤 이유로 이것은 나를 위해 작동 environment.getProperty("server.port")하지 않았습니다.
Anand Rockzz 2018

24

저를 올바른 방향으로 안내 해준 @Dirk Lachowski에게 감사드립니다. 솔루션은 내가 원했던 것만 큼 우아하지는 않지만 제대로 작동했습니다. 스프링 문서를 읽으면서 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();
      }
    }

AFAIK 서버 포트로 빈을 구성하려는 경우 작동하지 않습니다. 이 이벤트는 모든 빈이로드되고 서블릿이 등록 될 때까지 발생하지 않습니다.
mre

그것은 그 당시 나를 위해 일했습니다. 나는 hennr의 대답을 시도하지 않았습니다.
Tucker

문서를 읽은 후 나는 당신과 거의 같은 작은 클래스를 생각 해냈고 이름을 지정 PortProvider하고 getPort()방법을 제공했습니다 . 내 autowire가 PortProvider포트를 필요로하는 컨트롤러에, 그리고 내 비즈니스 로직을 호출 할 때 portProvider.getPort(), 런타임 포트가 반환되었습니다.
Matthew Wise

11
Spring Boot 2.0 이상에서 이것을 시도하는 사람에게는 API가 약간 변경된 것 같습니다. 더 이상 구독 할 수 EmbeddedServletContainerInitializedEvent없었지만 메서드 가있는 비슷한 클래스 ServletWebServerInitializedEvent.getWebServer()있습니다. 그러면 Tomcat이 최소한 수신하는 포트를 얻을 수 있습니다.
NiteLite

17

저와 같이 앱을 구성한 다른 사람들이 제가 겪은 일로부터 혜택을 얻도록 ...

위의 솔루션 중 어느 것도 ./config내 프로젝트 기반 바로 아래에 2 개의 파일 이있는 디렉토리 가 있기 때문에 효과가 없었습니다 .

application.properties
application-dev.properties

In application.propertiesI have :

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

에서 application-dev.propertiesI 있습니다 :

server_host = localhost
server_port = 8080

이것은 CLI에서 내 fat jar를 실행할 때 *.properties파일이 ./configdir 에서 읽히고 모든 것이 좋습니다.

음, 이러한 속성 파일 은 내 Spock 사양 의 webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT설정을 완전히 무시하는 것으로 나타났습니다 @SpringBootTest. 내가 무엇을 시도 했든간에 Spring 으로 webEnvironment설정 하더라도 RANDOM_PORT항상 포트 8080 (또는 내 ./config/*.properties파일에 설정 한 값)에서 포함 된 Tomcat 컨테이너를 시작합니다 .

내가 이것을 극복 할 수 있는 유일한 방법 은 내 Spock 통합 사양 properties = "server_port=0"@SpringBootTest주석에 명시 적을 추가하는 것입니다 .

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

그런 다음 Spring은 마침내 임의의 포트에서 Tomcat을 스핀 업하기 시작했습니다. IMHO 이것은 Spring 테스트 프레임 워크 버그이지만 그들 자신의 의견을 가질 것이라고 확신합니다.

이것이 누군가를 도왔기를 바랍니다.


이 똑같은 설정을 가지고 이것도 만났습니다. 나는 이것이 어떤 의미에서 문제라고 생각했지만 여기에 솔루션을 게시 해 주셔서 감사합니다. 아무도 이것을 버그로 기록했는지 알고 있습니까?
bvulaj

15

다음과 같이 local.server.port 값을 삽입하여 테스트 중에 포함 된 Tomcat 인스턴스에서 사용중인 포트를 가져올 수 있습니다.

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

17
local.server.port로 실행할 때만 설정됩니다.@WebIntegrationTests
ejain

WebIntegrationTest 는 더 이상 사용되지 않습니다.
kyakya

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;

  // ...
}

8

이 솔루션 중 어느 것도 나를 위해 일하지 않았습니다. Swagger 구성 빈을 구성하는 동안 서버 포트를 알아야했습니다. 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         
    }
}

이 예제는 Spring Boot 자동 구성 및 JAX-RS (Spring MVC 아님)를 사용합니다.


1
나는 자신감을 위해 같은 일을 원
Jeef

1

Spring Boot 2 이후 많은 것이 변경되었습니다. 위에 주어진 답변은 Spring Boot 2 이전에 작동합니다. 이제 서버 포트에 대한 런타임 인수를 사용하여 애플리케이션을 실행 @Value("${server.port}")하는 경우 application.properties 파일에 언급 된 정적 값만 얻을 수 있습니다. 이제 서버가 실행중인 실제 포트를 가져 오려면 다음 방법을 사용하십시오.

    @Autowired
    private ServletWebServerApplicationContext server;

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

        return "" + server.getWebServer().getPort();
    }

또한로드 밸런싱이있는 Eureka / Discovery 클라이언트로 애플리케이션을 사용하는 경우 RestTemplate또는 WebClient위의 방법은 정확한 포트 번호를 반환합니다.


1
이것은 Spring Boot 2에 대한 정답입니다. @SpringBootTest 및 WebEnvironment.RANDOM_PORT에서 잘 작동합니다.
Ken Pronovici

1

서버 포트는

HttpServletRequest
@Autowired
private HttpServletRequest request;

@GetMapping(value = "/port")
public Object getServerPort() {
   System.out.println("I am from " + request.getServerPort());
   return "I am from  " + request.getServerPort();
}
    

0

올바른 패키지를 가져 왔는지 확인하십시오

import org.springframework.core.env.Environment;

그런 다음 Environment 객체를 사용하십시오.

@Autowired
private Environment env;    // Environment Object containts the port number

 @GetMapping("/status")
  public String status()
    {
   return "it is runing on"+(env.getProperty("local.server.port"));
    }

1
내 답변을 변경했는데 여전히 같은 문제가 있습니까?
Ahmed

0

나는 일종의 프록시 빈으로 그것을 해결했습니다. 클라이언트는 필요할 때 초기화되고 포트를 사용할 수 있어야합니다.

@Component
public class GraphQLClient {

    private ApolloClient apolloClient;
    private final Environment environment;

    public GraphQLClient(Environment environment) {
        this.environment = environment;
    }

    public ApolloClient getApolloClient() {
        if (apolloClient == null) {
            String port = environment.getProperty("local.server.port");
            initApolloClient(port);
        }
        return apolloClient;
    }

    public synchronized void initApolloClient(String port) {
        this.apolloClient = ApolloClient.builder()
                .serverUrl("http://localhost:" + port + "/graphql")
                .build();
    }

    public <D extends Operation.Data, T, V extends Operation.Variables> GraphQLCallback<T> graphql(Operation<D, T, V> operation) {
        GraphQLCallback<T> graphQLCallback = new GraphQLCallback<>();
        if (operation instanceof Query) {
            Query<D, T, V> query = (Query<D, T, V>) operation;
            getApolloClient()
                    .query(query)
                    .enqueue(graphQLCallback);
        } else {
            Mutation<D, T, V> mutation = (Mutation<D, T, V>) operation;
            getApolloClient()
                    .mutate(mutation)
                    .enqueue(graphQLCallback);

        }
        return graphQLCallback;
    }
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.