私はSpringBootアプリケーション(組み込みのTomcat 7を使用)を持っており、ランダムなポートを持つことができるように設定server.port = 0
しましたapplication.properties
。サーバーを起動してポートで実行した後、選択したポートを取得できるようにする必要があります。
@Value("$server.port")
ゼロなので使えません。これは一見単純な情報ですが、Javaコードからアクセスできないのはなぜですか?どうすればアクセスできますか?
私はSpringBootアプリケーション(組み込みのTomcat 7を使用)を持っており、ランダムなポートを持つことができるように設定server.port = 0
しましたapplication.properties
。サーバーを起動してポートで実行した後、選択したポートを取得できるようにする必要があります。
@Value("$server.port")
ゼロなので使えません。これは一見単純な情報ですが、Javaコードからアクセスできないのはなぜですか?どうすればアクセスできますか?
回答:
同様の方法で管理ポートにアクセスすることも可能ですか?例:
@SpringBootTest(classes = {Application.class}, webEnvironment = WebEnvironment.RANDOM_PORT)
public class MyTest {
@LocalServerPort
int randomServerPort;
@LocalManagementPort
int randomManagementPort;
@LocalServerPort
のショートカットです@Value("${local.server.port}")
。
Spring'sEnvironmentはこの情報を保持します。
@Autowired
Environment environment;
String port = environment.getProperty("local.server.port");
表面的には、これは注釈付きのフィールド@Value("${local.server.port}")
(または@LocalServerPort
、同一)を挿入するのと同じように見えます。これにより、コンテキストが完全に初期化されるまで値が使用できないため、起動時に自動配線の失敗がスローされます。ここでの違いは、この呼び出しがアプリケーションの起動時に呼び出されるのではなく、ランタイムビジネスロジックで暗黙的に行われるため、ポートの「レイジーフェッチ」が正常に解決されることです。
environment.getProperty("server.port")
はうまくいきませんでした。
私を正しい方向に向けてくれた@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();
}
}
PortProvider
、それに名前を付け、getPort()
メソッドを提供しました。PortProvider
ポートを必要とするコントローラーに自動配線し、ビジネスロジックが呼び出されるportProvider.getPort()
と、ランタイムポートが返されました。
EmbeddedServletContainerInitializedEvent
同様のクラスがあります。これにより、Tomcatが少なくともリッスンしているポートが取得されます。ServletWebServerInitializedEvent
.getWebServer()
私のようなアプリを構成した他の人は、私が経験したことから恩恵を受けています...
私が持っているので、上記の解決策のどれも私のために働いていない./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
すると、ファイルが./config
dirから読み取られ、すべてが正常であるためです。
さて、これらのプロパティファイルは私の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テストフレームワークのバグですが、彼らはこれについて独自の意見を持っていると確信しています。
これが誰かを助けたことを願っています。
local.server.port値を次のように挿入することにより、テスト中に組み込みTomcatインスタンスによって使用されているポートを取得できます。
// Inject which port we were assigned
@Value("${local.server.port}")
int port;
local.server.port
で実行している場合にのみ設定されます@WebIntegrationTests
これらの解決策はどれも私にはうまくいきませんでした。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ではない)を使用しています。
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クライアントとして使用している場合、上記のメソッドは正確なポート番号を返します。
正しいパッケージをインポートしたことを確認してください
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"));
}
一種のプロキシ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;
}
}