SpringBoot-実行中のポートを取得する方法


91

私はSpringBootアプリケーション(組み込みの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 2015年

回答:


97

同様の方法で管理ポートにアクセスすることも可能ですか?例:

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

    @LocalServerPort
    int randomServerPort;

    @LocalManagementPort
    int randomManagementPort;

8
@LocalServerPortのショートカットです@Value("${local.server.port}")
デーモン2018

1
手段@deamonあなたがプロパティでlocal.server.portを指定しない場合-それは作品を習慣
スタンドアローン

82

Spring'sEnvironmentはこの情報を保持します。

@Autowired
Environment environment;

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

表面的には、これは注釈付きのフィールド@Value("${local.server.port}")(または@LocalServerPort、同一)を挿入するのと同じように見えます。これにより、コンテキストが完全に初期化されるまで値が使用できないため、起動時に自動配線の失敗がスローされます。ここでの違いは、この呼び出しがアプリケーションの起動時に呼び出されるのではなく、ランタイムビジネスロジックで暗黙的に行われるため、ポートの「レイジーフェッチ」が正常に解決されることです。


4
どういうわけか、これは私にenvironment.getProperty("server.port")はうまくいきませんでした。
Anand Rockzz 2018年

25

私を正しい方向に向けてくれた@DirkLachowskiに感謝します。解決策は私が望んでいたほどエレガントではありませんが、私はそれを機能させました。Springのドキュメントを読んで、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();
      }
    }

サーバーポートを使用してBeanを構成する場合、これは機能しません。このイベントは、すべてのBeanがロードされ、サーブレットが登録されるまで発生しません。
mre 2016

それは私がそれを受け入れた理由である時に私のために働いた。しかし、私はhennrの答えを試していません。
タッカー

ドキュメントを読んだ後、私はあなたと実質的に同じ小さなクラスを思いつきPortProvider、それに名前を付け、getPort()メソッドを提供しました。PortProviderポートを必要とするコントローラーに自動配線し、ビジネスロジックが呼び出されるportProvider.getPort()と、ランタイムポートが返されました。
マシューワイズ

12
Spring Boot 2.0以降でこれを試している人にとっては、APIが少し変更されているようです。サブスクライブできなくなりましたが、メソッドを持つEmbeddedServletContainerInitializedEvent同様のクラスがあります。これにより、Tomcatが少なくともリッスンしているポートが取得されます。ServletWebServerInitializedEvent.getWebServer()
NiteLite 2017

17

私のようなアプリを構成した他の人は、私が経験したことから恩恵を受けています...

私が持っているので、上記の解決策のどれも私のために働いていない./configだけで2つのファイルと私のプロジェクトベースの下のディレクトリを:

application.properties
application-dev.properties

application.properties私が持っています:

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

application-dev.properties、私があります。

server_host = localhost
server_port = 8080

これは、CLIからfat jarを実行*.propertiesすると、ファイルが./configdirから読み取られ、すべてが正常であるためです。

さて、これらのプロパティファイルは私のSpock仕様のwebEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT設定を 完全に上書きすることが@SpringBootTestわかりました。何を試しても、SpringにwebEnvironment設定してもRANDOM_PORT、埋め込みTomcatコンテナは常にポート8080(または./config/*.propertiesファイルに設定した値)で起動します。

ONLY私はこれを克服することができた方法は、明示的に追加することによりだったproperties = "server_port=0"@SpringBootTest私のスポック統合スペックで注釈:

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

その後、SpringはついにランダムポートでTomcatの起動を開始しました。私見これはSpringテストフレームワークのバグですが、彼らはこれについて独自の意見を持っていると確信しています。

これが誰かを助けたことを願っています。


これとまったく同じ設定をして、これにも遭遇しました。これはある意味で問題だと思いましたが、ここに解決策を投稿していただきありがとうございます。誰かがこれをバグとしてログに記録したかどうか知っていますか?
bvulaj

16

local.server.port値を次のように挿入することにより、テスト中に組み込みTomcatインスタンスによって使用されているポートを取得できます。

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

17
local.server.portで実行している場合にのみ設定されます@WebIntegrationTests
ejain 2015

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構成Beanを構築するときに、サーバーポートを知る必要がありました。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 2018年

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

また、アプリケーションを負荷分散RestTemplateまたはWebClientでEureka / Discoveryクライアントとして使用している場合、上記のメソッドは正確なポート番号を返します。


1
これはSpringBoot2の正解です。@ SpringBootTestおよびWebEnvironment.RANDOM_PORTで正常に機能します。
KenPronovici20年

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
私は私の答えに変更を加えました、あなたはまだ同じ問題を抱えていますか?
アーメド

0

一種のプロキシBeanで解決しました。クライアントは必要なときに初期化され、それまでにポートが使用可能になります。

@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.