Springsの新しいリアクティブwebflux拡張機能を使用して、クライアントとサーバーアプリケーション間の通信を確立したい。
依存関係の管理にはgradleを使用します。サーバーとクライアント側のbuild.gradleファイルは基本的に次のとおりです。
buildscript {
repositories {
mavenCentral()
maven { url "https://repo.spring.io/snapshot" }
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:2.0.0.BUILD-SNAPSHOT")
}
}
repositories {
mavenCentral()
maven { url "https://repo.spring.io/snapshot" }
}
apply plugin: 'Java'
apply plugin: 'org.springframework.boot'
apply plugin: "io.spring.dependency-management"
dependencies {
compile("org.springframework.boot:spring-boot-starter-webflux")
}
(2.0.0.BUILD -[〜#〜] snapshot [〜#〜]は動くターゲットであり、当面の問題は依存関係内の変更により1日消えます)
サーバー側アプリケーションを起動すると、組み込みのnettyサーバーの起動を含め、すべてがうまく起動します。
ただし、クライアントアプリケーションを起動すると、nettyサーバーも起動し、「Java.net.BindException:Address already in use」が発生します。これは、クライアント側のnettyサーバーがサーバー側のnettyサーバーと同じポートでリッスンするためです。
私の質問は次のとおりですなぜ最初にクライアント側でnettyが開始され、どうすればそれを防ぐことができますか?
Spring-Bootドキュメントによると、SpringはWebサポートが必要かどうかを判断し、それに応じてSpringアプリケーションコンテキストを構成します。
また、ドキュメントによると、これはsetWebEnvironment(false)の呼び出しによってオーバーライドできます。クライアントの起動コードは次のようになります。
@SpringBootApplication(scanBasePackages = { "com.tatics.flux.main" })
public class Client {
public static void main(String[] args) throws Exception {
SpringApplication app = new SpringApplication(Client.class);
app.setWebEnvironment(false);
app.run(Client.class, args);
WebClient webClient = WebClient.create();
Mono<String> result = webClient
.post()
.uri("http://localhost:8080/fluxService")
// This does not work any more: .body("Hallo")
// and must be replaced by:
.body(BodyInserters.fromObject("Hallo"))
.accept(MediaType.TEXT_PLAIN)
.exchange()
.flatMap(response -> response.bodyToMono(String.class));
}
}
残念ながら、nettyはまだ起動しています。また、setWebEnvironment(false)が非推奨としてマークされていることにも注意します。
Nettyが起動しないようにするが、それ以外のすべてのwebflux依存関係を維持する方法についての助けがあれば、高く評価されます。
自動構成レポートからの抜粋を以下に示します。
=========================
AUTO-CONFIGURATION REPORT
=========================
Positive matches:
-----------------
...
ReactiveWebServerAutoConfiguration matched:
- found ReactiveWebApplicationContext (OnWebApplicationCondition)
ReactiveWebServerAutoConfiguration#defaultReactiveWebServerCustomizer matched:
- @ConditionalOnMissingBean (types: org.springframework.boot.autoconfigure.web.reactive.DefaultReactiveWebServerCustomizer; SearchStrategy: all) did not find any beans (OnBeanCondition)
ReactiveWebServerConfiguration.ReactorNettyAutoConfiguration matched:
- @ConditionalOnClass found required class 'reactor.ipc.netty.http.server.HttpServer'; @ConditionalOnMissingClass did not find unwanted class (OnClassCondition)
- @ConditionalOnMissingBean (types: org.springframework.boot.web.reactive.server.ReactiveWebServerFactory; SearchStrategy: all) did not find any beans (OnBeanCondition)
ReactorCoreAutoConfiguration matched:
- @ConditionalOnClass found required classes 'reactor.core.publisher.Mono', 'reactor.core.publisher.Flux'; @ConditionalOnMissingClass did not find unwanted class (OnClassCondition)
...
Negative matches:
-----------------
...
ReactiveWebServerConfiguration.JettyAutoConfiguration:
Did not match:
- @ConditionalOnClass did not find required class 'org.Eclipse.jetty.server.Server' (OnClassCondition)
ReactiveWebServerConfiguration.TomcatAutoConfiguration:
Did not match:
- @ConditionalOnClass did not find required class 'org.Apache.catalina.startup.Tomcat' (OnClassCondition)
ReactiveWebServerConfiguration.UndertowAutoConfiguration:
Did not match:
- @ConditionalOnClass did not find required class 'io.undertow.Undertow' (OnClassCondition)
...
ReactiveWebServerConfiguration.JettyAutoConfiguration:
Did not match:
- @ConditionalOnClass did not find required class 'org.Eclipse.jetty.server.Server' (OnClassCondition)
ReactiveWebServerConfiguration.TomcatAutoConfiguration:
Did not match:
- @ConditionalOnClass did not find required class 'org.Apache.catalina.startup.Tomcat' (OnClassCondition)
ReactiveWebServerConfiguration.UndertowAutoConfiguration:
Did not match:
- @ConditionalOnClass did not find required class 'io.undertow.Undertow' (OnClassCondition)
コードの主な問題は、現在SpringApplication
を作成していて、それをカスタマイズして、最終的にすべてを削除して静的メソッドrun(Object primarySource, String... args)
を実行することです。
以下はうまくいくはずです:
@SpringBootApplication
public class Client {
public static void main(String[] args) throws Exception {
SpringApplication app = new SpringApplication(Client.class);
app.setWebApplicationType(WebApplicationType.NONE);
app.run(args);
}
@Bean
public CommandLineRunner myCommandLineRunner() {
return args -> {
// we have to block here, since command line runners don't
// consume reactive types and simply return after the execution
String result = WebClient.create("http://localhost:8080")
.post()
.uri("/fluxService")
.body("Hallo")
.accept(MediaType.TEXT_PLAIN)
.retrieve()
.bodyToMono(String.class)
.block();
// print the result?
};
}
}
そうでない場合は、--debug
フラグを使用してアプリケーションを実行し、自動構成レポートの関連部分、特にサーバーを扱う自動構成を質問に追加してください。
@Brian_Clozelの回答への追加:
Application.yml内で指定することにより、Netty(またはその他のサーバー)を無効にすることができます:
spring.main.web-application-type: none
またはapplication.properties:
spring.main.web-application-type=none