マイクロサービスフレームワークHelidonの使用について
20157 ワード
前期準備ゼロ
バージョン0
JDKバージョン:OpenJDK 11.0.1
IDE : idea 2018.3
Helidon Webserver:helidon-webserver 1.0.0(コア依存パッケージ)
Helidon Json:helidon-media-jsonp-server 1.0.0(jsonサポートパッケージ)
1 Helidonの概要
HelidonはOracle公式出品のjavaマイクロサービスフレームワークであり、下位層はNetty駆動に基づいており、大まかな使用方法とVertxの差は多くない(筆者はVertxを浅く理解しているだけで、理解できない場合があるかもしれない).2019年の初め、Helidonは1.0.0のバージョン更新を迎え、apiは安定し始めた.
現在のバージョンでは、OracleはHelidonが小さくて美しい軽量javaフレームワークであることを望んでいるはずなので、パッケージは非常に薄く、Nettyに対してカスタマイズされた処理を行っただけで、jdkの関連インタフェースを深く統合しています(結局は自分のもので、制御能力は普通ではありません).jsonの処理でもjavaxのjoupを参照して、サードパーティのツールパッケージを使用するのではありません.
Helidonの現在のネットワーク資料は少ないので,本稿では主にその公式文書を通じてDemoの構築を行う.
一構成
Helidonのコンフィギュレーションクラスには、コンフィギュレーションファイルを読み込むためのConfigと、サーバオブジェクトを構成するためのServer Configurationの2種類があります.
まずConfigを見てみましょう.
ServerConfigurationを見てみましょう.
にじゅうろ
ネットワークブログの最も簡単なHello Worldのルーティングオブジェクト:
ビジネスロジックを組み合わせたルーティング・オブジェクト:
HelloServiceでは、特定のビジネスロジックを処理します.
3サーバオブジェクト
サーバオブジェクト:
四サービス実現
まずWebServerのcreate()メソッドを見てみましょう.
NettyWebServerのコンストラクタコードは、本質的にはセグメントNettyの起動テンプレートコードです.
主にマルチプロファイルによるマルチイニシエータのニーズを互換化するためにforループを行いました.多くの場合、構成オブジェクトは1つしかなく、イニシエータは1つしかありません.
一方、他のセグメントNettyテンプレートコードはstart()メソッドにあります.
メーデーの小言
・Helidonフレームワークには、Security、Data Sourceなど、他にも多くのコンポーネントがあり、引き続き検討する必要がある
・おしゃれで軽くて、実はNettyを簡単にパッケージして、多くのコンポーネントもjdkで直接持っています
・json部分はjavax.jsonパッケージのツールを利用していますが、個人的には第三者より使いやすいとは思いません
・現在のところ、Oracleが上昇しているだけで、コミュニティの熱がまだ足りず、潜在力値が推定できない
六サービス・エンドのすべてのコード
バージョン0
JDKバージョン:OpenJDK 11.0.1
IDE : idea 2018.3
Helidon Webserver:helidon-webserver 1.0.0(コア依存パッケージ)
Helidon Json:helidon-media-jsonp-server 1.0.0(jsonサポートパッケージ)
1 Helidonの概要
HelidonはOracle公式出品のjavaマイクロサービスフレームワークであり、下位層はNetty駆動に基づいており、大まかな使用方法とVertxの差は多くない(筆者はVertxを浅く理解しているだけで、理解できない場合があるかもしれない).2019年の初め、Helidonは1.0.0のバージョン更新を迎え、apiは安定し始めた.
現在のバージョンでは、OracleはHelidonが小さくて美しい軽量javaフレームワークであることを望んでいるはずなので、パッケージは非常に薄く、Nettyに対してカスタマイズされた処理を行っただけで、jdkの関連インタフェースを深く統合しています(結局は自分のもので、制御能力は普通ではありません).jsonの処理でもjavaxのjoupを参照して、サードパーティのツールパッケージを使用するのではありません.
Helidonの現在のネットワーク資料は少ないので,本稿では主にその公式文書を通じてDemoの構築を行う.
一構成
Helidonのコンフィギュレーションクラスには、コンフィギュレーションファイルを読み込むためのConfigと、サーバオブジェクトを構成するためのServer Configurationの2種類があります.
まずConfigを見てみましょう.
//
Config conf = Config
//builder
.builder()
// ,
.sources(
//
ConfigSources.file("D://application.yaml"),
// resource
ConfigSources.classpath("application2.yaml")
)
//
.build();
ServerConfigurationを見てみましょう.
// ,
ServerConfiguration config = ServerConfiguration
// builder
.builder()
//address
//getLoopbackAddress() localhost
.bindAddress(InetAddress.getLoopbackAddress())
//getLocalHost() ip
//.bindAddress(InetAddress.getLocalHost())
//
.port(8080)
//
.workersCount(10)
// ServerConfiguration
//.addSocket("serverConfiguration",ServerConfiguration.builder().build())
//
//.config(conf)
//
.build();
にじゅうろ
ネットワークブログの最も簡単なHello Worldのルーティングオブジェクト:
//
Routing rt = Routing
//builder
.builder()
//
//
.anyOf(List.of(Http.Method.GET, Http.Method.POST,Http.Method.DELETE),"/hello",(req, res) -> res.send("hello world"))
//
//.post("/hello",(req, res) -> res.send("hello world"))
//.get("/hello",(req, res) -> res.send("hello world"))
//
.build();
ビジネスロジックを組み合わせたルーティング・オブジェクト:
//
Routing routing = Routing
//builder
.builder()
// json
.register(JsonSupport.create())
// url ,
// service
.post("/hello", Handler.create(JsonObject.class,new HelloService()))
//hello world
.get("/hello1",(req, res) -> res.send("hello world"))
//
.build();
HelloServiceでは、特定のビジネスロジックを処理します.
//HelloService Handler.EntityHandler
class HelloService implements Handler.EntityHandler{
//json
private static final JsonBuilderFactory jsonFactory = Json.createBuilderFactory(Collections.emptyMap());
// , , send(...) response
@Override
public void accept(ServerRequest req, ServerResponse res, Object entity) {
//entity JsonObject
JsonObject reqJson = (JsonObject)entity;
// , Fastjson
String ret = reqJson.getString("hello");
System.out.println(ret);
// json object
JsonObject msg = jsonFactory
//builder
.createObjectBuilder()
// json key - value
.add("message", "Hello")
// json
.build();
//json array
//JsonArray array = jsonFactory.createArrayBuilder().build();
//
res.send(msg);
}
}
3サーバオブジェクト
サーバオブジェクト:
//
WebServer
//
// ServerConfiguration Routing
.create(config,routing)
//
.start()
// future
.toCompletableFuture()
// 10
.get(10, TimeUnit.SECONDS);
四サービス実現
まずWebServerのcreate()メソッドを見てみましょう.
//step 1
//WebServer.class
static WebServer create(ServerConfiguration configuration, Routing routing) {
//
Objects.requireNonNull(routing, "Parameter 'routing' is null!");
//builder(...) WebServer.Builder , build() WebServer
return builder(routing).config(configuration)
.build();
}
//step 2
//WebServer.Builder.class
public WebServer build() {
//routings Map ,
String unpairedRoutings = routings
.keySet()
.stream()
.filter(routingName -> configuration == null || configuration.socket(routingName) == null)
.collect(Collectors.joining(", "));
//
if (!unpairedRoutings.isEmpty()) {
throw new IllegalStateException("No server socket configuration found for named routings: " + unpairedRoutings);
}
//NettyWebServer WebServer
//defaultRouting create(...)
WebServer result = new NettyWebServer(configuration == null
? ServerBasicConfig.DEFAULT_CONFIGURATION
: configuration,
defaultRouting, routings);
// RequestRouting
//
if (defaultRouting instanceof RequestRouting) {
((RequestRouting) defaultRouting).fireNewWebServer(result);
}
//
return result;
}
//step 3
//NettyWebServer.class
NettyWebServer(ServerConfiguration config,
Routing routing,
Map namedRoutings) {
// SocketConfiguration
// addSocket(...) ,
Set> sockets = config.sockets().entrySet();
//
this.bossGroup = new NioEventLoopGroup(sockets.size());
this.workerGroup = config.workersCount() <= 0 ? new NioEventLoopGroup() : new NioEventLoopGroup(config.workersCount());
this.configuration = config;
// , ServerBootstrap
for (Map.Entry entry : sockets) {
String name = entry.getKey();
SocketConfiguration soConfig = entry.getValue();
ServerBootstrap bootstrap = new ServerBootstrap();
JdkSslContext sslContext = null;
if (soConfig.ssl() != null) {
sslContext = new JdkSslContext(soConfig.ssl(), false, ClientAuth.NONE);
}
if (soConfig.backlog() > 0) {
bootstrap.option(ChannelOption.SO_BACKLOG, soConfig.backlog());
}
if (soConfig.timeoutMillis() > 0) {
bootstrap.option(ChannelOption.SO_TIMEOUT, soConfig.timeoutMillis());
}
if (soConfig.receiveBufferSize() > 0) {
bootstrap.option(ChannelOption.SO_RCVBUF, soConfig.receiveBufferSize());
}
//childHandler handler,
HttpInitializer childHandler = new HttpInitializer(sslContext, namedRoutings.getOrDefault(name, routing), this);
// handler
initializers.add(childHandler);
// Netty
bootstrap.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.handler(new LoggingHandler(LogLevel.DEBUG))
.childHandler(childHandler);
//
bootstraps.put(name, bootstrap);
}
}
NettyWebServerのコンストラクタコードは、本質的にはセグメントNettyの起動テンプレートコードです.
主にマルチプロファイルによるマルチイニシエータのニーズを互換化するためにforループを行いました.多くの場合、構成オブジェクトは1つしかなく、イニシエータは1つしかありません.
一方、他のセグメントNettyテンプレートコードはstart()メソッドにあります.
//NettyWebServer.class
public synchronized CompletionStage start() {
//started boolean ,
if (!started) {
channelsUpFuture.thenAccept(startFuture::complete)
.exceptionally(throwable -> {
if (channels.isEmpty()) {
startFailureHandler(throwable);
}
for (Channel channel : channels.values()) {
channel.close();
}
return null;
});
channelsCloseFuture.whenComplete((webServer, throwable) -> shutdown(throwable));
// NettyWebServer Netty
Set> bootstrapEntries = bootstraps.entrySet();
int bootstrapsSize = bootstrapEntries.size();
for (Map.Entry entry : bootstrapEntries) {
ServerBootstrap bootstrap = entry.getValue();
String name = entry.getKey();
SocketConfiguration socketConfig = configuration.socket(name);
if (socketConfig == null) {
throw new IllegalStateException(
"no socket configuration found for name: " + name);
}
int port = socketConfig.port() <= 0 ? 0 : socketConfig.port();
if (channelsUpFuture.isCompletedExceptionally()) {
break;
}
try {
//bootstrap
//Helidon Netty
bootstrap.bind(configuration.bindAddress(), port).addListener(channelFuture -> {
if (!channelFuture.isSuccess()) {
LOGGER.info(() -> "Channel '" + name + "' startup failed with message '"
+ channelFuture.cause().getMessage() + "'.");
channelsUpFuture.completeExceptionally(new IllegalStateException("Channel startup failed: " + name,
channelFuture.cause()));
return;
}
Channel channel = ((ChannelFuture) channelFuture).channel();
LOGGER.info(() -> "Channel '" + name + "' started: " + channel);
channels.put(name, channel);
channel.closeFuture().addListener(future -> {
LOGGER.info(() -> "Channel '" + name + "' closed: " + channel);
channels.remove(name);
if (channelsUpFuture.isCompletedExceptionally()) {
if (channels.isEmpty()) {
channelsUpFuture.exceptionally(this::startFailureHandler);
} else if (future.cause() != null) {
LOGGER.log(Level.WARNING,
"Startup failure channel close failure",
new IllegalStateException(future.cause()));
}
} else {
if (!future.isSuccess()) {
channelsCloseFuture.completeExceptionally(new IllegalStateException("Channel stop failure.",
future.cause()));
} else if (channels.isEmpty()) {
channelsCloseFuture.complete(this);
}
}
});
if (channelsUpFuture.isCompletedExceptionally()) {
channel.close();
}
if (channels.size() >= bootstrapsSize) {
LOGGER.finer(() -> "All channels started: " + channels.size());
channelsUpFuture.complete(this);
}
});
} catch (RejectedExecutionException e) {
if (shutdownThreadGroupsInitiated.get()) {
break;
} else {
throw e;
}
}
}
started = true;
LOGGER.fine(() -> "All channels startup routine initiated: " + bootstrapsSize);
}
// CompletableFuture
return startFuture;
}
メーデーの小言
・Helidonフレームワークには、Security、Data Sourceなど、他にも多くのコンポーネントがあり、引き続き検討する必要がある
・おしゃれで軽くて、実はNettyを簡単にパッケージして、多くのコンポーネントもjdkで直接持っています
・json部分はjavax.jsonパッケージのツールを利用していますが、個人的には第三者より使いやすいとは思いません
・現在のところ、Oracleが上昇しているだけで、コミュニティの熱がまだ足りず、潜在力値が推定できない
六サービス・エンドのすべてのコード
import io.helidon.common.http.Http;
import io.helidon.config.Config;
import io.helidon.config.ConfigSources;
import io.helidon.media.jsonp.server.JsonSupport;
import io.helidon.webserver.*;
import javax.json.Json;
import javax.json.JsonBuilderFactory;
import javax.json.JsonObject;
import java.net.InetAddress;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
public class HelidonService {
public void run() throws InterruptedException, ExecutionException, TimeoutException {
//
// Config conf = Config
//
// //builder
// .builder()
//
// // ,
// .sources(
// //
// ConfigSources.file("D://application.yaml"),
// // resource
// ConfigSources.classpath("application2.yaml")
// )
//
// //
// .build();
ServerConfiguration c = ServerConfiguration.builder().build();
// ,
ServerConfiguration config = ServerConfiguration
// builder
.builder()
//address
//getLoopbackAddress() localhost
.bindAddress(InetAddress.getLoopbackAddress())
//getLocalHost() ip
//.bindAddress(InetAddress.getLocalHost())
//
.port(8080)
//
.workersCount(10)
// ServerConfiguration
//.addSocket("serverConfiguration",ServerConfiguration.builder().build())
//
//.config(conf)
//
.build();
//
// Routing rt = Routing
//
// //builder
// .builder()
//
// //
// //
// .anyOf(List.of(Http.Method.GET, Http.Method.POST),"/hello",(req, res) -> res.send("hello world"))
//
// //
// //.post("/hello",(req, res) -> res.send("hello world"))
// //.get("/hello",(req, res) -> res.send("hello world"))
//
// //
// .build();
//
Routing routing = Routing
//builder
.builder()
// json
.register(JsonSupport.create())
// url ,
// service
.post("/hello", Handler.create(JsonObject.class,new HelloService()))
//hello world
.get("/hello1",(req, res) -> res.send("hello world"))
//
.build();
//
WebServer
//
.create(config,routing)
//
.start()
// future
.toCompletableFuture()
//
.get(10, TimeUnit.SECONDS);
}
//main
public static void main(String[] args) throws InterruptedException, ExecutionException, TimeoutException {
new HelidonService().run();
}
}
class HelloService implements Handler.EntityHandler{
//json
private static final JsonBuilderFactory jsonFactory = Json.createBuilderFactory(Collections.emptyMap());
@Override
public void accept(ServerRequest req, ServerResponse res, Object entity) {
//entity JsonObject
JsonObject reqJson = (JsonObject)entity;
// , Fastjson
String ret = reqJson.getString("hello");
System.out.println(ret);
// json object
JsonObject msg = jsonFactory
//builder
.createObjectBuilder()
// json key - value
.add("message", "Hello")
// json
.build();
//json array
//JsonArray array = jsonFactory.createArrayBuilder().build();
//
res.send(msg);
}
}