主頁 > 軟體設計 > Netty權威指南(二)NIO模型

Netty權威指南(二)NIO模型

2021-03-03 16:57:16 軟體設計

NIO目錄

  • 一、NIO編程
  • 二、NIO類別庫和相關概念
    • 緩沖區Buffer
    • 通道Channel
    • 多路復用器Selector
  • 三、NIO服務端流程分析
  • 四、NIO客戶端流程分析
  • 五、NIO編程的優點
  • 原始碼
    • TimeServer
    • MultiplexerTimeServer
    • TimeClient
    • TimeClientHandle

一、NIO編程

NIO有兩種叫法:有人稱之為New I/O;更多的人喜歡稱之為Non-block I/O:非阻塞I/O,后者更能體現NIO的特點,
SocketServerSocket類相對應,NIO也提供了SocketChannelServerSocketChannel兩種不同的套接字通道實作,這兩種新增的通道都支持阻塞與非阻塞兩種模式,一般來說:低負載、低并發的應用程式可以選擇同步阻塞I/O以降低編程復雜度;對于高負載、高并發的應用程式,需要使用NIO的非阻塞模式進行開發,

二、NIO類別庫和相關概念

在Java1.4之前的早期版本,Java對I/O的支持并不完善,開發人員在開發高性能I/O程式的時候,會面臨一些巨大的挑戰和困難,主要問題如下:

  1. 沒有資料緩沖區,I/O性能存在問題,
  2. 沒有Channel通道的概念,只有輸入和輸出流,
  3. 同步阻塞式I/O通信(BIO),通常會導致通信執行緒被長時間阻塞,
  4. 支持的字符集有限,硬體可移植性不好,

NIO 主要有三大核心部分:Channel(通道),Buffer(緩沖區), Selector,傳統 IO 基于位元組流和字 符流進行操作,而 NIO 基于 Channel 和 Buffer(緩沖區)進行操作,資料總是從通道讀取到緩沖區中,或者從緩沖區寫入到通道中,

NIO 和傳統 IO 之間第一個最大的區別是,IO 是面向流的,NIO 是面向緩沖區的,

緩沖區Buffer

Buffer是一個物件,它包含一些要寫入或者要讀出的資料,在NIO類別庫中加入Buffer物件,體現了新庫與原來I/O的一個重要區別,在面向流的IO中,可以將資料直接寫入或者將資料直接得到Stream物件中,
在NIO庫中,所有資料都是用緩沖區處理的,在讀取資料時,他是直接讀到緩沖區的;在寫入資料時,寫入帶緩沖區中,任何時候訪問NIO中的資料都是通過緩沖區進行操作,
緩沖區實質上是一個陣列,通常它是一個位元組陣列(ByteBuffer),也可以使用其他種類的陣列,但是一個緩沖區不僅僅是一個陣列,緩沖區提供了對資料的結構化訪問以及維護讀寫位置(limit)等資訊,
最常用的是ByteBuffer,一個ByteBuffer提供了一組功能用于操作byte陣列,每一種Java基本型別都對應有一種緩沖區(除了Boolean),
ByteBuffer、CharBuffer、ShortBuffer、IntBuffer、LongBuffer、FloatBuffer、DoubleBuffer,

通道Channel

Channel是一個通道,它就像一個自來水管一樣,網路資料通過Channel都讀取和寫入,通道和流的不同之處在于通道是雙向的,流只是在一個方向上移動(一個流必須是InputStream或者OutputStream的子類),而通道可以用于讀、寫或者二者同時進行,Channel是雙全工的,同時支持讀寫操作,

多路復用器Selector

多路復用器Selector是JavaNIO編程的基礎,簡單來講:Selector會不斷輪詢注冊在其上的Channel,如果某個Channel上面發生事件,這個Channel就處于就緒狀態,會被Selector輪詢出來,然后通過SelectorKey可以獲取就緒Channel的集合,進行后續的I/O操作,
一個多路復用器Selector可以同時輪詢多個Channel,只需要一個執行緒負責Selector的輪詢,就可以接入成百上千的客戶端,

三、NIO服務端流程分析

  1. 打開ServerSocketChannel,用于監聽客戶端的連接,它是所有客戶端連接的父管道,
  2. 系結監聽埠,設定連接為非阻塞模式,
  3. 創建Reactor執行緒創建多路復用器Selector并啟動執行緒,
  4. ServerSocketChannel注冊到Reactor執行緒的多路復用器Selector上,監聽ACCEPT事件,
  5. 多路復用器Selector在執行緒run方法的無限回圈體內輪詢準備就緒的Key,
  6. 多路復用器Selector監聽到有新的客戶端接入,處理新的請求,完成TCP三次握手,建立物理鏈路,
  7. 設定客戶端鏈路為非阻塞模式,
  8. 將新接入的客戶端連接注冊到Reactor執行緒的多路復用器上,監聽操作,
  9. 異步讀取客戶端請求訊息到緩沖區,
  10. 對ByteBuffer進行編解碼,如果有半包訊息指標reset,繼續讀取后續的報文,將解碼成功的訊息封裝成Task,投遞到業務執行緒池中,進行業務邏輯編排,
  11. 將POJO物件encode成ByteBuffer,呼叫SocketChannel的異步write介面,將訊息異步發送給客戶端,

四、NIO客戶端流程分析

  1. 打開SocketChannel,系結客戶端本地地址,
  2. 設定SocketChannel為非阻塞模式,同時設定客戶端連接的TCP引數
  3. 異步連接服務端
  4. 判斷連接是否成功,如果連接成功,則直接注冊讀狀態位到多路復用器Selector中,如果當前沒有連接成功(異步連接,回傳false,說明客戶端已經發送sync包,服務端沒有回傳ack包,物理鏈路還沒有建立)
  5. 向Reactor執行緒的多路復用器注冊OP_CONNECT狀態位,監聽服務端的TCP ACK應答,
  6. 創建Reactor執行緒,創建多路復用器Selector并啟動執行緒,
  7. 多路復用器在執行緒run方法的無限回圈體內輪詢準備就緒的key,
  8. 接收connect事件進行處理,
  9. 判斷連接結果,如果連接成功,注冊讀事件到多路復用器,
  10. 異步讀客戶端請求訊息到緩沖區,
  11. 對ByteBuffer進行編解碼,如果有半包訊息接識訓沖區Reset,繼續讀取后續的提交,將解碼成功的訊息封裝成Task,投遞到業務執行緒池中,進行業務邏輯編排,
  12. 將POJO物件encode成ByteBuffer,呼叫SocketChannel的異步write介面將訊息異步發送給客戶端,

在這里插入圖片描述

五、NIO編程的優點

NIO編程的難度確實比同步阻塞的BIO編程大很多,我們的NIO實體沒有考慮“半包讀”和“半包寫”,如果加上這些,代碼將會更加復雜,既然代碼這么復雜,為什么它的應用卻越來越廣泛呢?使用NIO編程的優點總結如下:

  1. 客戶端發起的連接時異步的,可以通過在多路復用器注冊OP_CONNECT等待后續結果,不需要像之的客戶端那樣被同步阻塞,
  2. SocketChannel的讀寫操作都是異步的,如果沒有可讀寫的資料它不會同步等待,直接回傳,這樣IO通信執行緒就可以處理其他的鏈路,不需要同步等待這個鏈路可用,
  3. 執行緒模型的優化,由于JDK的Selector在Linux等主流作業系統上通過epoll實作,它沒有連接句柄數的限制(只受限于作業系統的最大句柄數或者對單個行程的句柄限制),這意味著一個Selector執行緒可以同時處理成千上萬個客戶端連接,而且性能不會隨著客戶端的增加而線性下降,因此,它非常適合做高性能、高負載的網路服務器,

原始碼

TimeServer

創建一個多路復用類(MultiplexerTimeServer),是一個獨立負責的執行緒,負責輪詢多路復用器Selector,可以處理多個客戶端的并發接入,

public class TimeServer {
    public static void main(String[] args) {
        int port = 8080;
        MultiplexerTimeServer timeServer =  new MultiplexerTimeServer(port);
        new Thread(timeServer,"NIO-MultiplexerTimeServer-001").start();
    }

}

MultiplexerTimeServer

package com.lsh.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Date;
import java.util.Iterator;
import java.util.Set;

/**
 * @author :LiuShihao
 * @date :Created in 2021/3/1 12:03 下午
 * @desc :NIO時間服務器 MulitiplexerTimeServer  多路復用器
 * 它是一個獨立的執行緒,負責輪詢多路復用器Selector,可以處理多個客戶端的并發接入,
 */
public class MultiplexerTimeServer implements Runnable{

    private Selector selector;

    private ServerSocketChannel serverChannel;

    private volatile boolean stop;

    /**
     * 初始化多路復用器 系結監聽埠
     * 創建多路復用器Selector、ServerSocketChannel
     * 對Channel和TCP引數進行配置
     * @param port
     */
    public MultiplexerTimeServer(int port) {
        try {
            //創建Reactor執行緒,創建多路復用器
            selector = Selector.open();
            //打開ServerSocketChannel,用于監聽客戶端的連接,它是所有客戶端連接的父管道
            serverChannel = ServerSocketChannel.open();
            //將Channel設定為異步非阻塞模式,他的backlog設定為1024
            serverChannel.configureBlocking(false);
            //系結監聽介面
            serverChannel.socket().bind(new InetSocketAddress(port),1024);
            //將ServerSockrtChannel注冊到Reactor執行緒的多路復用器Selector上,監聽ACCEPT事件
            serverChannel.register(selector, SelectionKey.OP_ACCEPT);
            System.out.println("The time server is start in port :"+port);

        } catch (IOException e) {
            e.printStackTrace();
            //如果資源初始化失敗,如埠被占用,則退出
            System.exit(1);
        }

    }

    public void stop(){
        this.stop = true;
    }

    @Override
    public void run() {

        /**
         * 多路復用器在run方法的無限回圈體中內輪詢準備就緒的key
         * 在while回圈體中,回圈遍歷selector,休眠時間為1秒,無論是否有讀寫時間發生,selector每隔1s都被喚醒1次
         * 當有處于就緒狀態的Channel時,selector將回傳該Channel的SelectionKey集合,通過對就緒狀態的Channel集合進行迭代,可以進行網路的異步讀寫操作,
         */
        while(!stop){
            try {
                selector.select(1000);
                Set<SelectionKey> selectionKeys = selector.selectedKeys();
                Iterator<SelectionKey> it = selectionKeys.iterator();
                SelectionKey key = null;
                while(it.hasNext()){
                    key = it.next();
                    it.remove();
                    try{
                        handlerInput(key);
                    }catch (Exception e){
                        if (key != null){
                            key.cancel();
                            if (key.channel() != null){
                                key.channel().close();
                            }
                        }
                    }

                }

            } catch (Throwable t) {
                t.printStackTrace();
            }

        }
        //多路復用器關閉 后,所有注冊在上面的Channel和Pipe等資源都會被自動用去注冊并關閉,所以不需要重復釋放資源
        if (selector != null){
            try {
                selector.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }

    /**
     * 根據SelectorKey的操作位進行判斷即可獲知網路時間的型別,
     * @param key
     * @throws IOException
     */
    private void handlerInput(SelectionKey key) throws IOException{
        if (key.isValid()){
            //處理新接入的訊息請求
            if (key.isAcceptable()){
                //Accept the new connection
                ServerSocketChannel ssc = (ServerSocketChannel) key.channel();
                //通過ServerSocketChannel的accept接收客戶端的鏈接請求并創建SocketChannel實體,相當于完成了TCP的三次握手,TCP物理鏈路正式建立,
                SocketChannel sc = ssc.accept();
                //需要將新創建的SocketChannel設定為異步非阻塞,同時也可以對其TCP引數進行設定,例如TCP接收和發送緩沖區的大小等,但作為入門的例子,沒有進行額外的引數設定,
                sc.configureBlocking(false);
                // Add the new connection to the selector
                //將新接入的客戶端連接注冊到Reactor執行緒的多路復用器上,監聽讀操作,讀取客戶端發送的網路訊息,
                sc.register(selector,SelectionKey.OP_READ);
            }
            if (key.isReadable()){
                //Read the data
                SocketChannel sc = (SocketChannel) key.channel();
                ByteBuffer readBuffer = ByteBuffer.allocate(1024);
                // 異步讀取客戶端訊息到緩沖區
                int readBytes = sc.read(readBuffer);
                if (readBytes > 0){
                    readBuffer.flip();
                    byte[] bytes = new byte[readBuffer.remaining()];
                    readBuffer.get(bytes);
                    String body = new String(bytes, "UTF-8");
                    System.out.println("The time server receive order :"+body);
                    String currentTime = "QUERY TIME ORDER".equalsIgnoreCase(body) ? new Date(System.currentTimeMillis()).toString() : "BAD ORDER";
                    doWrite(sc,currentTime);
                } else if (readBytes < 0 ){
                    //對端鏈路關閉
                    key.cancel();
                    sc.close();
                }else {
                    ;//讀到0位元組,忽略
                }
            }

        }

    }

    private void doWrite(SocketChannel channel, String response) throws IOException{
        if (response != null && response.trim().length() > 0 ){
            //將訊息encode成ByteBuffer,呼叫SocketChannel的異步write介面,將訊息異步發送給客戶端,
            byte[] bytes = response.getBytes();
            ByteBuffer writeBuffer = ByteBuffer.allocate(bytes.length);
            writeBuffer.put(bytes);
            writeBuffer.flip();
            channel.write(writeBuffer);
        }

    }
}

TimeClient

public class TimeClient {

    public static void main(String[] args) {
        int port = 8080;
        //通過創建TimeClient執行緒來處理異步連接和讀寫操作
        new Thread(new TimeClientHandle("127.0.0.1",port),"TimeClinet-001").start();
    }
}

TimeClientHandle

package com.lsh.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;

/**
 * @author :LiuShihao
 * @date :Created in 2021/3/1 2:18 下午
 * @desc :NIO時間服務器客戶端 Handle
 */
public class TimeClientHandle  implements Runnable {
    private String host;
    private int port;
    private Selector selector;
    private SocketChannel socketChannel;
    private volatile  boolean stop;





    public TimeClientHandle(String host, int port) {
        this.host = host == null ? "127.0.0.1" : host;
        this.port = port;
        try {
            selector = Selector.open();
            socketChannel = SocketChannel.open();
            socketChannel.configureBlocking(false);
        } catch (IOException e) {
            e.printStackTrace();
            System.exit(1);
        }
    }

    @Override
    public void run() {
        try{
            doConnect();
        }catch (Exception e){
            e.printStackTrace();
            System.exit(1);
        }
        while(!stop){
            try{
                selector.select(1000);
                Set<SelectionKey> selectionKeys = selector.selectedKeys();
                Iterator<SelectionKey> it = selectionKeys.iterator();
                SelectionKey key = null;
                while(it.hasNext()){
                    key = it.next();
                    it.remove();
                    try{
                        handleInput(key);
                    }catch (Exception e){
                        if (key != null){
                            key.cancel();
                            if (key.channel() != null){
                                key.channel().close();
                            }
                        }
                    }
                }
            }catch (Exception e){
                e.printStackTrace();
                System.exit(1);
            }
        }
        // 多路復用器關閉后,所有注冊在上面的Channel和Pige等資源都會被自動去注冊并關閉,所以不需要重讀釋放資源,
        if (selector != null){
            try{
                selector.close();
            }catch (Exception e){
                e.printStackTrace();
            }
        }

    }

    private void handleInput(SelectionKey key) throws IOException{
        if (key.isValid()){
            //判斷是否連接成功
            SocketChannel sc = (SocketChannel) key.channel();
            if (key.isConnectable()){
                if (sc.finishConnect()){
                    sc.register(selector,SelectionKey.OP_READ);
                    doWrite(sc);
                }else {
                    //連接失敗,行程退出
                    System.exit(1);
                }
            }
            if (key.isReadable()){
                ByteBuffer readBuffer = ByteBuffer.allocate(1024);
                int readBytes = sc.read(readBuffer);
                if (readBytes > 0 ){
                    readBuffer.flip();
                    byte[] bytes = new byte[readBuffer.remaining()];
                    readBuffer.get(bytes);
                    String body = new String(bytes,"UTF-8");
                    System.out.println("Now is :"+body);
                    this.stop = true;
                } else if (readBytes < 0 ){
                    key.cancel();
                    sc.close();
                }else {
                    ;//讀到0位元組,忽略
                }

            }
        }

    }



    private void doConnect() throws IOException{
        //如果直接連接成功,則注冊到多路復用器上,發送請求訊息,讀應答
        if (socketChannel.connect(new InetSocketAddress(host,port))){
            socketChannel.register(selector,SelectionKey.OP_READ);
            doWrite(socketChannel);
        }else {
            socketChannel.register(selector,SelectionKey.OP_CONNECT);
        }
    }

    private void doWrite(SocketChannel sc) throws IOException{
        byte[] req = "QUERY TIME ORDER".getBytes();
        ByteBuffer writeBuffer = ByteBuffer.allocate(req.length);
        writeBuffer.put(req);
        writeBuffer.flip();
        sc.write(writeBuffer);
        if (!writeBuffer.hasRemaining()){
            System.out.println("Send order 2 server succeed.");
        }

    }
}

轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/265444.html

標籤:其他

上一篇:CVPR 2021 結果出爐!最全論文下載(更新中)

下一篇:用VSCode終端實作重定向比較程式輸出和正確輸出

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 面試突擊第一季,第二季,第三季

    第一季必考 https://www.bilibili.com/video/BV1FE411y79Y?from=search&seid=15921726601957489746 第二季分布式 https://www.bilibili.com/video/BV13f4y127ee/?spm_id_fro ......

    uj5u.com 2020-09-10 05:35:24 more
  • 第三單元作業總結

    1.前言 這應該是本學期最后一次寫作業總結了吧。總體來說,對作業的節奏也差不多掌握了,作業做起來的效率也更高了。雖然和之前的作業一樣,作業中都要用到新的知識,但是相比之前,更加懂得了如何利用工具以及資料。雖然之間卡過殼,但總體而言,這幾次作業還算完成的比較好。 2.作業程序總結 相比前兩個單元,此單 ......

    uj5u.com 2020-09-10 05:35:41 more
  • 北航OO(2020)第四單元博客作業暨課程總結博客

    北航OO(2020)第四單元博客作業暨課程總結博客 本單元作業的架構設計 在本單元中,由于UML圖具有比較清晰的樹形結構,因此我對其中需要進行查詢操作的元素進行了包裝,在樹的父節點中存盤所有孩子的參考。考慮到性能問題,我采用了快取機制,一次查詢后盡可能快取已經遍歷過的資訊,以減少遍歷次數。 本單元我 ......

    uj5u.com 2020-09-10 05:35:48 more
  • BUAA_OO_第四單元

    一、UML決議器設計 ? 先看下題目:第四單元實作一個基于JDK 8帶有效性檢查的UML(Unified Modeling Language)類圖,順序圖,狀態圖分析器 MyUmlInteraction,實際上我們要建立一個有向圖模型,UML中的物件(元素)可能與同級元素連接,也可與低級元素相連形成 ......

    uj5u.com 2020-09-10 05:35:54 more
  • 6.1邏輯運算子

    邏輯運算子 1. && 短路與 運算式1 && 運算式2 01.運算式1為true并且運算式2也為true 整體回傳為true 02.運算式1為false,將不會執行運算式2 整體回傳為false 03.只要有一個運算式為false 整體回傳為false 2. || 短路或 運算式1 || 運算式2 ......

    uj5u.com 2020-09-10 05:35:56 more
  • BUAAOO 第四單元 & 課程總結

    1. 第四單元:StarUml檔案決議 本單元采用了圖模型決議UML。 UML檔案可以抽象為圖、子圖、邊的邏輯結構。 在實作中,圖的節點包括類、介面、屬性,子圖包括狀態圖、順序圖等。 采用了三次遍歷UML元素的方法建圖,第一遍遍歷建點,第二、三次遍歷設定屬性、連邊,實作圖物件的初始化。這里借鑒了一些 ......

    uj5u.com 2020-09-10 05:36:06 more
  • 談談我對C# 多型的理解

    面向物件三要素:封裝、繼承、多型。 封裝和繼承,這兩個比較好理解,但要理解多型的話,可就稍微有點難度了。今天,我們就來講講多型的理解。 我們應該經常會看到面試題目:請談談對多型的理解。 其實呢,多型非常簡單,就一句話:呼叫同一種方法產生了不同的結果。 具體實作方式有三種。 一、多載 多載很簡單。 p ......

    uj5u.com 2020-09-10 05:36:09 more
  • Python 資料驅動工具:DDT

    背景 python 的unittest 沒有自帶資料驅動功能。 所以如果使用unittest,同時又想使用資料驅動,那么就可以使用DDT來完成。 DDT是 “Data-Driven Tests”的縮寫。 資料:http://ddt.readthedocs.io/en/latest/ 使用方法 dd. ......

    uj5u.com 2020-09-10 05:36:13 more
  • Python里面的xlrd模塊詳解

    那我就一下面積個問題對xlrd模塊進行學習一下: 1.什么是xlrd模塊? 2.為什么使用xlrd模塊? 3.怎樣使用xlrd模塊? 1.什么是xlrd模塊? ?python操作excel主要用到xlrd和xlwt這兩個庫,即xlrd是讀excel,xlwt是寫excel的庫。 今天就先來說一下xl ......

    uj5u.com 2020-09-10 05:36:28 more
  • 當我們創建HashMap時,底層到底做了什么?

    jdk1.7中的底層實作程序(底層基于陣列+鏈表) 在我們new HashMap()時,底層創建了默認長度為16的一維陣列Entry[ ] table。當我們呼叫map.put(key1,value1)方法向HashMap里添加資料的時候: 首先,呼叫key1所在類的hashCode()計算key1 ......

    uj5u.com 2020-09-10 05:36:38 more
最新发布
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:20:47 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:20:25 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:20:17 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:20:10 more
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:19:44 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:19:07 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:18:57 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:18:49 more
  • 05單件模式

    #經典的單件模式 public class Singleton { private static Singleton uniqueInstance; //一個靜態變數持有Singleton類的唯一實體。 // 其他有用的實體變數寫在這里 //構造器宣告為私有,只有Singleton可以實體化這個類! ......

    uj5u.com 2023-04-19 08:42:51 more
  • 【架構與設計】常見微服務分層架構的區別和落地實踐

    軟體工程的方方面面都遵循一個最基本的道理:沒有銀彈,架構分層模型更是如此,每一種都有各自優缺點,所以請根據不同的業務場景,并遵循簡單、可演進這兩個重要的架構原則選擇合適的架構分層模型即可。 ......

    uj5u.com 2023-04-19 08:42:41 more