国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

淺析微服務框架 Helidon 的使用

dockerclub / 1922人閱讀

摘要:零前期準備版本版本核心依賴包支持包簡介是官方出品的微服務框架,底層基于驅動,大致的使用套路和相差不是很多筆者只是淺淺的了解過,可能存在理解不透的情況。一配置中的配置類有兩種,一種是用于讀取配置文件的,另一種是用于配置服務器對象的。

零 前期準備 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,另一種是用于配置服務器對象的 ServerConfiguration。

先來看 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);
    }
}
三 服務器對象

服務器對象:

//啟動服務器
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 循環。在多數時候其實就只有一個配置對象,也就只有一個啟動器。

而另外半段 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 在自 high,社區熱度還不夠,潛力值不好估計

六 服務端全部代碼
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);
    }
}

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/73710.html

相關文章

  • Oracle發布開源輕量級 Java 服務框架 Helidon

    摘要:近日,推出了一個新的開源框架,該項目是一個用于創建基于微服務的應用程序的庫集合。下圖說明了和所屬的微服務框架類別。啟用后,會將其跟蹤事件發送到。 近日,Oracle推出了一個新的開源框架Helidon,該項目是一個用于創建基于微服務的應用程序的Java庫集合。和Payara Micro、Thorntail(之前的WildFly Swarm)、OpenLiberty、TomEE等項目一樣...

    Benedict Evans 評論0 收藏0
  • 墻裂推薦:搜云庫技術團隊,面試必備技術干貨

    摘要:今天整理了一下近大半年以來的一些文章,和我的預期一樣,很多文章我都忘記自己曾經寫過了,這個記錄的過程讓我也有了新的理解。希望大家,收藏,點贊,加轉發。 今天整理了一下近大半年以來的一些文章,和我的預期一樣,很多文章我都忘記自己曾經寫過了,這個記錄的過程讓我也有了新的理解。希望大家,收藏,點贊,加轉發。 面試必備 面試必備:深入Spring MVC DispatchServlet 源碼...

    SegmentFault 評論0 收藏0
  • 墻裂推薦:搜云庫技術團隊,面試必備技術干貨

    摘要:今天整理了一下近大半年以來的一些文章,和我的預期一樣,很多文章我都忘記自己曾經寫過了,這個記錄的過程讓我也有了新的理解。希望大家,收藏,點贊,加轉發。 今天整理了一下近大半年以來的一些文章,和我的預期一樣,很多文章我都忘記自己曾經寫過了,這個記錄的過程讓我也有了新的理解。希望大家,收藏,點贊,加轉發。 面試必備 面試必備:深入Spring MVC DispatchServlet 源碼...

    Neilyo 評論0 收藏0
  • 【推薦】最新200篇:技術文章整理

    摘要:作為面試官,我是如何甄別應聘者的包裝程度語言和等其他語言的對比分析和主從復制的原理詳解和持久化的原理是什么面試中經常被問到的持久化與恢復實現故障恢復自動化詳解哨兵技術查漏補缺最易錯過的技術要點大掃盲意外宕機不難解決,但你真的懂數據恢復嗎每秒 作為面試官,我是如何甄別應聘者的包裝程度Go語言和Java、python等其他語言的對比分析 Redis和MySQL Redis:主從復制的原理詳...

    BicycleWarrior 評論0 收藏0

發表評論

0條評論

最新活動
閱讀需要支付1元查看
<