成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專欄INFORMATION COLUMN

淺析微服務(wù)框架 Helidon 的使用

dockerclub / 1991人閱讀

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

零 前期準(zhǔn)備 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 微服務(wù)框架,底層基于 Netty 驅(qū)動,大致的使用套路和 Vertx 相差不是很多(筆者只是淺淺的了解過 Vertx,可能存在理解不透的情況)。在 2019 年的年初,Helidon 迎來了 1.0.0 的版本更新,api 開始趨于穩(wěn)定。

就目前的版本來看,Oracle 應(yīng)該希望 Helidon 是一個小而美的輕巧型 java 框架,所以對其的封裝非常之薄,僅僅是對 Netty 做了一層定制化的處理,同時也深度整合了 jdk 的相關(guān)接口(畢竟是自家的東西,駕馭能力不一般)。就連 json 的處理都引用了 javax 中的 joup 去做,而不是使用第三方工具包。

Helidon 目前的網(wǎng)絡(luò)資料很少,所以本文主要通過其官方文檔進(jìn)行 Demo 的構(gòu)筑。

一 配置

Helidon 中的配置類有兩種,一種是用于讀取配置文件的 Config,另一種是用于配置服務(wù)器對象的 ServerConfiguration。

先來看 Config:

//配置文件
Config conf = Config

                    //builder
                    .builder()

                    //載入配置文件,可以一次載入多張
                    .sources(
                            //根據(jù)絕對路徑去載入配置文件
                            ConfigSources.file("D://application.yaml"),
                            //到 resource 文件夾下去尋找
                            ConfigSources.classpath("application2.yaml")
                    )

                    //創(chuàng)建完成
                    .build();

再來看 ServerConfiguration:

//創(chuàng)建一個配置對象,用于注入一些配置信息
ServerConfiguration config = ServerConfiguration

                                                //生成 builder
                                                .builder()

                                                //address

                                                //getLoopbackAddress() 會獲取到 localhost
                                                .bindAddress(InetAddress.getLoopbackAddress())

                                                //getLocalHost() 會獲取到本機的 ip
                                                //.bindAddress(InetAddress.getLocalHost())

                                                //端口
                                                .port(8080)

                                                //工作線程的線程數(shù)
                                                .workersCount(10)

                                                //增加一個 ServerConfiguration 對象
                                                //.addSocket("serverConfiguration",ServerConfiguration.builder().build())

                                                //載入配置文件
                                                //.config(conf)

                                                //創(chuàng)建完成
                                                .build();
二 路由

網(wǎng)絡(luò)博文最簡單的 Hello World 的路由對象:

//創(chuàng)建最簡單的路由邏輯
Routing rt = Routing

                    //builder
                    .builder()

                    //設(shè)置路由的請求方法和業(yè)務(wù)邏輯
                    //設(shè)置多種請求方法
                    .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"))

                    //創(chuàng)建完成
                    .build();

結(jié)合業(yè)務(wù)邏輯的路由對象:

//創(chuàng)建路由對象
Routing routing = Routing

                        //builder
                        .builder()

                        //注冊 json 解析器
                        .register(JsonSupport.create())

                        //添加 url 路由,一個路由對象可以添加多個

                        //可以添加業(yè)務(wù)邏輯的 service 類
                        .post("/hello", Handler.create(JsonObject.class,new HelloService()))

                        //hello world
                        .get("/hello1",(req, res) -> res.send("hello world"))

                        //創(chuàng)建完成
                        .build();

HelloService 中處理具體的業(yè)務(wù)邏輯:

//HelloService 必須實現(xiàn) Handler.EntityHandler
class HelloService implements Handler.EntityHandler{

    //json 的解析門面對象
    private static final JsonBuilderFactory jsonFactory = Json.createBuilderFactory(Collections.emptyMap());

    //核心業(yè)務(wù)類,里面可以寫具體的業(yè)務(wù)邏輯,最后 send(...) 進(jìn) response 里就可以了
    @Override
    public void accept(ServerRequest req, ServerResponse res, Object entity) {

        //entity 本質(zhì)上就是 JsonObject
        JsonObject reqJson = (JsonObject)entity;

        //獲取鍵值對并打印,這個操作和 Fastjson 很類似
        String ret = reqJson.getString("hello");
        System.out.println(ret);

        //創(chuàng)建要返回的 json object
        JsonObject msg = jsonFactory

                                //builder
                                .createObjectBuilder()

                                //添加一組 json 的 key - value 鍵值對
                                .add("message", "Hello")

                                //創(chuàng)建 json 對象完成
                                .build();

        //json array 的創(chuàng)建方式
        //JsonArray array = jsonFactory.createArrayBuilder().build();

        //返回
        res.send(msg);
    }
}
三 服務(wù)器對象

服務(wù)器對象:

//啟動服務(wù)器
WebServer

        //創(chuàng)建服務(wù)器對象
        //具體依賴 ServerConfiguration 和 Routing 對象
        .create(config,routing)

        //開啟服務(wù)器
        .start()

        //獲取 future
        .toCompletableFuture()

        //設(shè)置超時時間為 10 秒
        .get(10, TimeUnit.SECONDS);
四 服務(wù)實現(xiàn)

先來看 WebServer 的 create(...) 方法:

//step 1
//WebServer.class
static WebServer create(ServerConfiguration configuration, Routing routing) {
    //有效性驗證
    Objects.requireNonNull(routing, "Parameter "routing" is null!");

    //builder(...) 方法會創(chuàng)建一個 WebServer.Builder 對象,最終在 build() 方法里創(chuàng)建 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 接口的實現(xiàn)類
    //defaultRouting 是上方 create(...) 方法存入的路由對象
    WebServer result = new NettyWebServer(configuration == null
                                                    ? ServerBasicConfig.DEFAULT_CONFIGURATION
                                                    : configuration,
                                            defaultRouting, routings);
    
    //默認(rèn)的路由對象即為 RequestRouting 類型
    //此處給路由對象添加回調(diào)方法
    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();

    //創(chuàng)建兩個線程
    this.bossGroup = new NioEventLoopGroup(sockets.size());
    this.workerGroup = config.workersCount() <= 0 ? new NioEventLoopGroup() : new NioEventLoopGroup(config.workersCount());

    this.configuration = config;

    //循環(huán)所有的配置對象,然后分別創(chuàng)建 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 是核心的業(yè)務(wù) handler,使用者寫的業(yè)務(wù)邏輯也都在里面
        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 中的構(gòu)造器代碼其實本質(zhì)上就是半段 Netty 的啟動模板代碼。

主要是為了兼容多配置文件帶來的多啟動器需求,所以做了一個 for 循環(huán)。在多數(shù)時候其實就只有一個配置對象,也就只有一個啟動器。

而另外半段 Netty 模板代碼在 start(...) 方法中:

//NettyWebServer.class
public synchronized CompletionStage start() {

    //started 是一個 boolean 類型的變量,用來判斷該服務(wù)器對象是否啟動
    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 的構(gòu)造器中儲存下來的所有 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 的設(shè)置
                //Helidon 中用監(jiān)聽器方式去異步啟動 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 等,有待繼續(xù)研究

· 很時髦很輕巧,其實就是簡單封裝了一下 Netty,大多數(shù)的組件也是直接用 jdk 自帶的

· json 部分其實就是把 javax.json 包里的工具利用了一下,但是筆者個人覺得沒比第三方好用

· 目前來看僅僅是 Oracle 在自 high,社區(qū)熱度還不夠,潛力值不好估計

六 服務(wù)端全部代碼
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(
//                                    //根據(jù)絕對路徑去載入配置文件
//                                    ConfigSources.file("D://application.yaml"),
//                                    //到 resource 文件夾下去尋找
//                                    ConfigSources.classpath("application2.yaml")
//                            )
//
//                            //創(chuàng)建完成
//                            .build();

        ServerConfiguration c = ServerConfiguration.builder().build();

        //創(chuàng)建一個配置對象,用于注入一些配置信息
        ServerConfiguration config = ServerConfiguration

                                                        //生成 builder
                                                        .builder()

                                                        //address

                                                        //getLoopbackAddress() 會獲取到 localhost
                                                        .bindAddress(InetAddress.getLoopbackAddress())

                                                        //getLocalHost() 會獲取到本機的 ip
                                                        //.bindAddress(InetAddress.getLocalHost())

                                                        //端口
                                                        .port(8080)

                                                        //工作線程的線程數(shù)
                                                        .workersCount(10)

                                                        //增加一個 ServerConfiguration 對象
                                                        //.addSocket("serverConfiguration",ServerConfiguration.builder().build())

                                                        //載入配置文件
                                                        //.config(conf)

                                                        //創(chuàng)建完成
                                                        .build();

          //創(chuàng)建最簡單的路由邏輯
//        Routing rt = Routing
//
//                                //builder
//                                .builder()
//
//                                //設(shè)置路由的請求方法和業(yè)務(wù)邏輯
//                                //設(shè)置多種請求方法
//                                .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"))
//
//                                //創(chuàng)建完成
//                                .build();


        //創(chuàng)建路由對象
        Routing routing = Routing

                                //builder
                                .builder()

                                //注冊 json 解析器
                                .register(JsonSupport.create())

                                //添加 url 路由,一個路由對象可以添加多個

                                //可以添加業(yè)務(wù)邏輯的 service 類
                                .post("/hello", Handler.create(JsonObject.class,new HelloService()))

                                //hello world
                                .get("/hello1",(req, res) -> res.send("hello world"))

                                //創(chuàng)建完成
                                .build();

        //啟動服務(wù)器
        WebServer

                //創(chuàng)建服務(wù)器對象
                .create(config,routing)

                //開啟服務(wù)器
                .start()

                //獲取 future
                .toCompletableFuture()

                //設(shè)置超時時間
                .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 本質(zhì)上就是 JsonObject
        JsonObject reqJson = (JsonObject)entity;

        //獲取鍵值對并打印,這個操作和 Fastjson 很類似
        String ret = reqJson.getString("hello");
        System.out.println(ret);

        //創(chuàng)建要返回的 json object
        JsonObject msg = jsonFactory

                                //builder
                                .createObjectBuilder()

                                //添加一組 json 的 key - value 鍵值對
                                .add("message", "Hello")

                                //創(chuàng)建 json 對象完成
                                .build();

        //json array 的創(chuàng)建方式
        //JsonArray array = jsonFactory.createArrayBuilder().build();

        //返回
        res.send(msg);
    }
}

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://m.hztianpu.com/yun/73710.html

相關(guān)文章

  • Oracle發(fā)布開源輕量級 Java 服務(wù)框架 Helidon

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

    Benedict Evans 評論0 收藏0
  • 墻裂推薦:搜云庫技術(shù)團(tuán)隊,面試必備技術(shù)干貨

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

    SegmentFault 評論0 收藏0
  • 墻裂推薦:搜云庫技術(shù)團(tuán)隊,面試必備技術(shù)干貨

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

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

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

    BicycleWarrior 評論0 收藏0

發(fā)表評論

0條評論

閱讀需要支付1元查看
<