springboot之springboot與netty整合方案
1、簡單概述
Netty是一個高性能、異步事件驅(qū)動的NIO框架,基于JAVA NIO提供的API實(shí)現(xiàn)。
它提供了對TCP、UDP和文件傳輸?shù)闹С郑鳛橐粋€異步NIO框架,Netty的所有IO操作都是異步非阻塞的,通過Future-Listener機(jī)制,用戶可以方便的主動獲取或者通過通知機(jī)制獲得IO操作結(jié)果。
作為當(dāng)前最流行的NIO框架,Netty在互聯(lián)網(wǎng)領(lǐng)域、大數(shù)據(jù)分布式計算領(lǐng)域、游戲行業(yè)、通信行業(yè)等獲得了廣泛的應(yīng)用,一些業(yè)界著名的開源組件也基于Netty的NIO框架構(gòu)建。
Netty 對 JDK 自帶的 NIO 的 API 進(jìn)行封裝,解決上述問題,主要特點(diǎn)有:
- 設(shè)計優(yōu)雅,適用于各種傳輸類型的統(tǒng)一 API 阻塞和非阻塞 Socket;基于靈活且可擴(kuò)展的事件模型,可以清晰地分離關(guān)注點(diǎn);高度可定制的線程模型,單線程,一個或多個線程池;真正的無連接數(shù)據(jù)報套接字支持(自 3.1 起)。
- 使用方便,詳細(xì)記錄的 Javadoc,用戶指南和示例;沒有其他依賴項(xiàng),JDK 5(Netty 3.x)或 6(Netty 4.x)就足夠了。
- 高性能,吞吐量更高,延遲更低;減少資源消耗;最小化不必要的內(nèi)存復(fù)制。
- 安全,完整的 SSL/TLS 和 StartTLS 支持。
- 社區(qū)活躍,不斷更新,社區(qū)活躍,版本迭代周期短,發(fā)現(xiàn)的 Bug 可以被及時修復(fù),同時,更多的新功能會被加入。
2、IO模型
Netty 作為異步事件驅(qū)動的網(wǎng)絡(luò),高性能之處主要來自于其 I/O 模型和線程處理模型,前者決定如何收發(fā)數(shù)據(jù),后者決定如何處理數(shù)據(jù)。
I/O 復(fù)用模型:
在 I/O 復(fù)用模型中,會用到 Select,這個函數(shù)也會使進(jìn)程阻塞,但是和傳統(tǒng)的JAVA阻塞 I/O 所不同的是這兩個函數(shù)可以同時阻塞多個 I/O 操作。
而且可以同時對多個讀操作,多個寫操作的 I/O 函數(shù)進(jìn)行檢測,直到有數(shù)據(jù)可讀或可寫時,才真正調(diào)用 I/O 操作函數(shù)。
Netty 的非阻塞 I/O 的實(shí)現(xiàn)關(guān)鍵是基于 I/O 復(fù)用模型,這里用 Selector 對象表示:
Netty 的 IO 線程 NioEventLoop 由于聚合了多路復(fù)用器 Selector,可以同時并發(fā)處理成百上千個客戶端連接。
當(dāng)線程從某客戶端 Socket 通道進(jìn)行讀寫數(shù)據(jù)時,若沒有數(shù)據(jù)可用時,該線程可以進(jìn)行其他任務(wù)。
線程通常將非阻塞 IO 的空閑時間用于在其他通道上執(zhí)行 IO 操作,所以單獨(dú)的線程可以管理多個輸入和輸出通道。
由于讀寫操作都是非阻塞的,這就可以充分提升 IO 線程的運(yùn)行效率,避免由于頻繁 I/O 阻塞導(dǎo)致的線程掛起。
一個 I/O 線程可以并發(fā)處理 N 個客戶端連接和讀寫操作,這從根本上解決了傳統(tǒng)同步阻塞 I/O 一連接一線程模型,架構(gòu)的性能、彈性伸縮能力和可靠性都得到了極大的提升。
3、事件模型
下圖描述了Netty進(jìn)行事件處理的流程。
Channel是連接的通道,是ChannelEvent的產(chǎn)生者,而ChannelPipeline可以理解為ChannelHandler的集合。
在Netty里,所有事件都來自ChannelEvent接口,這些事件涵蓋監(jiān)聽端口、建立連接、讀寫數(shù)據(jù)等網(wǎng)絡(luò)通訊的各個階段。
而事件的處理者就是ChannelHandler,這樣,不但是業(yè)務(wù)邏輯,連網(wǎng)絡(luò)通訊流程中底層的處理,都可以通過實(shí)現(xiàn)ChannelHandler來完成了。
事實(shí)上,Netty內(nèi)部的連接處理、協(xié)議編解碼、超時等機(jī)制,都是通過handler完成的。
3、springboot與netty集成
3.1 添加netty+springboot依賴
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>io.netty</groupId> <artifactId>netty-all</artifactId> <version>4.1.28.Final</version> </dependency>
3.2 netty服務(wù)端配置
/** * 服務(wù)端基本配置,通過一個靜態(tài)單例類,保證啟動時候只被加載一次 */ @Component public class WsServer { /** * 單例靜態(tài)內(nèi)部類 */ public static class SingletionWServer{ static final WsServer instance = new WsServer(); } public static WsServer getInstance(){ return SingletionWServer.instance; } private EventLoopGroup mainGroup ; private EventLoopGroup subGroup; private ServerBootstrap server; private ChannelFuture future; public WsServer(){ mainGroup = new NioEventLoopGroup(); subGroup = new NioEventLoopGroup(); server = new ServerBootstrap(); server.group(mainGroup, subGroup) .channel(NioServerSocketChannel.class) .childHandler(new WsServerInitialzer());//添加自定義初始化處理器 } public void start(){ future = this.server.bind(8081); System.err.println("netty 服務(wù)端啟動完畢 ....."); } }
自定義初始化處理器: WsServerInitialzer
public class WsServerInitialzer extends ChannelInitializer<SocketChannel>{ @Override protected void initChannel(SocketChannel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); //websocket基于http協(xié)議,所以需要http編解碼器 pipeline.addLast(new HttpServerCodec()); //添加對于讀寫大數(shù)據(jù)流的支持 pipeline.addLast(new ChunkedWriteHandler()); //對httpMessage進(jìn)行聚合 pipeline.addLast(new HttpObjectAggregator(1024*64)); // ================= 上述是用于支持http協(xié)議的 ============== //websocket 服務(wù)器處理的協(xié)議,用于給指定的客戶端進(jìn)行連接訪問的路由地址 //比如處理一些握手動作(ping,pong) pipeline.addLast(new WebSocketServerProtocolHandler("/ws")); //自定義handler pipeline.addLast(new ChatHandler()); } }
自定義handler類: ChatHandler
/** * 上文中需要自定義處理的handler * TextWebSocketFrame 用于為websockt處理文本的對象 */ public class ChatHandler extends SimpleChannelInboundHandler<TextWebSocketFrame>{ //用于記錄和管理所有客戶端的channel private static ChannelGroup clients = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE); @Override protected void messageReceived(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception { //客戶端傳遞過來的消息 String content = msg.text(); System.out.println("接收到了客戶端的消息是:" + content); //將客戶端發(fā)送過來的消息刷到所有的channel中 for(Channel channel : clients){ channel.writeAndFlush( new TextWebSocketFrame("[服務(wù)器接收到了客戶端的消息:]" + LocalDateTime.now()+",消息為:" + content)); } } //客戶端創(chuàng)建的時候觸發(fā),當(dāng)客戶端連接上服務(wù)端之后,就可以獲取該channel,然后放到channelGroup中進(jìn)行統(tǒng)一管理 @Override public void handlerAdded(ChannelHandlerContext ctx) throws Exception { clients.add(ctx.channel()); } //客戶端銷毀的時候觸發(fā), @Override public void handlerRemoved(ChannelHandlerContext ctx) throws Exception { //當(dāng)handlerRemoved 被觸發(fā)時候,channelGroup會自動移除對應(yīng)的channel //clients.remove(ctx.channel()); System.out.println("客戶端斷開,當(dāng)前被移除的channel的短ID是:" +ctx.channel().id().asShortText()); } }
配置springboot啟動加載netty服務(wù)
/** * netty服務(wù)端啟動加載配置 */ @Component public class NettybootServerInitConfig implements ApplicationListener<ContextRefreshedEvent>{ @Override public void onApplicationEvent(ContextRefreshedEvent event) { if(event.getApplicationContext().getParent() == null){ WsServer.getInstance().start(); } } }
總結(jié)
以上為個人經(jīng)驗(yàn),希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
vue - vue.config.js中devServer配置方式
今天小編就為大家分享一篇vue - vue.config.js中devServer配置方式,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-10-10vue中給el-radio添加tooltip并實(shí)現(xiàn)點(diǎn)擊跳轉(zhuǎn)方式
這篇文章主要介紹了vue中給el-radio添加tooltip并實(shí)現(xiàn)點(diǎn)擊跳轉(zhuǎn)方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-04-04安裝vue無法運(yùn)行、此系統(tǒng)無法運(yùn)行腳本問題及解決
這篇文章主要介紹了安裝vue無法運(yùn)行、此系統(tǒng)無法運(yùn)行腳本問題及解決,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-03-03vue2.x?el-table二次封裝實(shí)現(xiàn)編輯修改
本文主要介紹了vue2.x?el-table二次封裝實(shí)現(xiàn)編輯修改,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-03-03Vue Element UI 中 el-table 樹形數(shù)據(jù) 
這篇文章主要介紹了Vue Element UI 中 el-table 樹形數(shù)據(jù) tree-props 多層級使用避坑指南,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友參考下吧2024-01-01圖文詳解Element-UI中自定義修改el-table樣式
elementUI提供的組件間距、樣式都比較大,如果直接套用,在頁面顯示可能就會顯得很大,就比如表格,表頭、行寬如果不修改的話,遇到列較多的時候,會顯得整個頁面就不好看,下面這篇文章主要給大家介紹了關(guān)于Element-UI中自定義修改el-table樣式的相關(guān)資料,需要的朋友可以參考下2022-08-08完美解決iview 的select下拉框選項(xiàng)錯位的問題
下面小編就為大家分享一篇完美解決iview 的select下拉框選項(xiàng)錯位的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-03-03