埋め込みのTomcat 7を使用したスプリングブートアプリケーションがあり、server.port = 0
にapplication.properties
を設定したため、ランダムなポートを使用できます。サーバーを起動してポートで実行した後、選択したポートを取得できるようにする必要があります。
@Value("$server.port")
はゼロなので使用できません。これは一見シンプルな情報ですが、Javaコードからアクセスできないのはなぜですか?どうすればアクセスできますか?
私を正しい方向に向けてくれた@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();
}
}
同様の方法で管理ポートにアクセスすることも可能ですか、例えば:
@SpringBootTest(classes = {Application.class}, webEnvironment = WebEnvironment.RANDOM_PORT)
public class MyTest {
@LocalServerPort
int randomServerPort;
@LocalManagementPort
int randomManagementPort;
Spring's Environmentはこの情報を保持します。
@Autowired
Environment environment;
String port = environment.getProperty("local.server.port");
表面的には、これは@Value("${local.server.port}")
(または@LocalServerPort
、同じ)アノテーションが付けられたフィールドの注入と同じに見えます。これにより、コンテキストが完全に初期化されるまで値が利用できないため、起動時に自動配線の失敗がスローされます。ここでの違いは、この呼び出しはアプリケーションの起動時に呼び出されるのではなく、実行時のビジネスロジックで暗黙的に行われるため、ポートの「遅延フェッチ」は問題なく解決することです。
Local.server.port値を次のように注入することにより、テスト中に埋め込みTomcatインスタンスによって使用されているポートを取得できます。
// Inject which port we were assigned
@Value("${local.server.port}")
int port;
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;
// ...
}
私のようにアプリを設定した他の人が私が経験したことの恩恵を受けるだけです...
上記の解決策はどれもうまくいきませんでした。なぜなら、プロジェクトベースのすぐ下に2つのファイルがある./config
ディレクトリがあるからです。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
設定を完全にオーバーライドすることがわかりました。 webEnvironment
がRANDOM_PORT
に設定されていても、Springはポート8080(または./config/*.properties
ファイルに設定した値)で常に埋め込みTomcatコンテナを起動します。
ONLY私がこれを克服できたのは、Spock統合仕様のproperties = "server_port=0"
アノテーションに明示的な@SpringBootTest
を追加することでした。
@SpringBootTest (webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, properties = "server_port=0")
その後、SpringはついにランダムポートでTomcatを起動し始めました。私見これはSpringテストフレームワークのバグですが、彼らはこれについて自分の意見を持っていると確信しています。
これが誰かを助けることを願っています。
これらのソリューションはどれも私にとってはうまくいきませんでした。 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ではありません)を使用します。