欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

SpringBoot項目中使用Netty實(shí)現(xiàn)遠(yuǎn)程調(diào)用的示例代碼

 更新時間:2025年04月20日 08:48:40   作者:程序員小假  
眾所周知在進(jìn)行網(wǎng)絡(luò)連接的時候,建立套接字連接是一個非常消耗性能的事情,特別是在分布式的情況下,那么該通過什么技術(shù)去解決上述的問題呢,本文小編給大家介紹了SpringBoot項目中使用Netty實(shí)現(xiàn)遠(yuǎn)程調(diào)用的方法,需要的朋友可以參考下

前言

眾所周知在進(jìn)行網(wǎng)絡(luò)連接的時候,建立套接字連接是一個非常消耗性能的事情,特別是在分布式的情況下,用線程池去保持多個客戶端連接,是一種非常消耗線程的行為。
那么該通過什么技術(shù)去解決上述的問題呢,那么就不得不提一個網(wǎng)絡(luò)連接的利器——Netty。 

正文

Netty

Netty是一個NIO客戶端服務(wù)器框架:

  • 它可快速輕松地開發(fā)網(wǎng)絡(luò)應(yīng)用程序,例如協(xié)議服務(wù)器和客戶端。
  • 它極大地簡化和簡化了網(wǎng)絡(luò)編程,例如TCP和UDP套接字服務(wù)器。

NIO是一種非阻塞IO ,它具有以下的特點(diǎn)

  • 單線程可以連接多個客戶端。

  • 選擇器可以實(shí)現(xiàn)但線程管理多個Channel,新建的通道都要向選擇器注冊。

  • 一個SelectionKey鍵表示了一個特定的通道對象和一個特定的選擇器對象之間的注冊關(guān)系。

  • selector進(jìn)行select()操作可能會產(chǎn)生阻塞,但是可以設(shè)置阻塞時間,并且可以用wakeup()喚醒selector,所以NIO是非阻塞IO。 

    Netty模型selector模式

    它相對普通NIO的在性能上有了提升,采用了:

  • NIO采用多線程的方式可以同時使用多個selector

  • 通過綁定多個端口的方式,使得一個selector可以同時注冊多個ServerSocketServer

  • 單個線程下只能有一個selector,用來實(shí)現(xiàn)Channel的匹配及復(fù)用

半包問題

TCP/IP在發(fā)送消息的時候,可能會拆包,這就導(dǎo)致接收端無法知道什么時候收到的數(shù)據(jù)是一個完整的數(shù)據(jù)。在傳統(tǒng)的BIO中在讀取不到數(shù)據(jù)時會發(fā)生阻塞,但是NIO不會。
為了解決NIO的半包問題,Netty在Selector模型的基礎(chǔ)上,提出了reactor模式,從而解決客戶端請求在服務(wù)端不完整的問題。 

Netty模型reactor模式

在selector的基礎(chǔ)上解決了半包問題。

上圖,簡單地可以描述為”boss接活,讓work干”:manReactor用來接收請求(會與客戶端進(jìn)行握手驗(yàn)證),而subReactor用來處理請求(不與客戶端直接連接)。 

SpringBoot使用Netty實(shí)現(xiàn)遠(yuǎn)程調(diào)用

依賴

<!--lombok-->
<dependency>
  <groupId>org.projectlombok</groupId>
  <artifactId>lombok</artifactId>
  <version>1.18.2</version>
  <optional>true</optional>
</dependency>
<!--netty-->
<dependency>
  <groupId>io.netty</groupId>
  <artifactId>netty-all</artifactId>
  <version>4.1.17.Final</version>
</dependency>

服務(wù)端部分

NettyServer.java:服務(wù)啟動監(jiān)聽器

@Slf4j
public class NettyServer {
    public void start() {
        InetSocketAddress socketAddress = new InetSocketAddress("127.0.0.1", 8082);
        //new 一個主線程組
        EventLoopGroup bossGroup = new NioEventLoopGroup(1);
        //new 一個工作線程組
        EventLoopGroup workGroup = new NioEventLoopGroup(200);
        ServerBootstrap bootstrap = new ServerBootstrap()
                .group(bossGroup, workGroup)
                .channel(NioServerSocketChannel.class)
                .childHandler(new ServerChannelInitializer())
                .localAddress(socketAddress)
                //設(shè)置隊列大小
                .option(ChannelOption.SO_BACKLOG, 1024)
                // 兩小時內(nèi)沒有數(shù)據(jù)的通信時,TCP會自動發(fā)送一個活動探測數(shù)據(jù)報文
                .childOption(ChannelOption.SO_KEEPALIVE, true);
        //綁定端口,開始接收進(jìn)來的連接
        try {
            ChannelFuture future = bootstrap.bind(socketAddress).sync();
            log.info("服務(wù)器啟動開始監(jiān)聽端口: {}", socketAddress.getPort());
            future.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            log.error("服務(wù)器開啟失敗", e);
        } finally {
            //關(guān)閉主線程組
            bossGroup.shutdownGracefully();
            //關(guān)閉工作線程組
            workGroup.shutdownGracefully();
        }
    }
}

ServerChannelInitializer.java:netty服務(wù)初始化器

/**
* netty服務(wù)初始化器
**/
public class ServerChannelInitializer extends ChannelInitializer<SocketChannel> {
    @Override
    protected void initChannel(SocketChannel socketChannel) throws Exception {
        //添加編解碼
        socketChannel.pipeline().addLast("decoder", new StringDecoder(CharsetUtil.UTF_8));
        socketChannel.pipeline().addLast("encoder", new StringEncoder(CharsetUtil.UTF_8));
        socketChannel.pipeline().addLast(new NettyServerHandler());
    }
}

NettyServerHandler.java:netty服務(wù)端處理器

/**
* netty服務(wù)端處理器
**/
@Slf4j
public class NettyServerHandler extends ChannelInboundHandlerAdapter {
    /**
     * 客戶端連接會觸發(fā)
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        log.info("Channel active......");
    }
    /**
     * 客戶端發(fā)消息會觸發(fā)
     */
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        log.info("服務(wù)器收到消息: {}", msg.toString());
        ctx.write("你也好哦");
        ctx.flush();
    }
    /**
     * 發(fā)生異常觸發(fā)
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        ctx.close();
    }
}

RpcServerApp.java:SpringBoot啟動類

/**
* 啟動類
*
*/
@Slf4j
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
public class RpcServerApp extends SpringBootServletInitializer {
    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(RpcServerApp.class);
    }
    /**
     * 項目的啟動方法
     *
     * @param args
     */
    public static void main(String[] args) {
        SpringApplication.run(RpcServerApp.class, args);
        //開啟Netty服務(wù)
        NettyServer nettyServer = new NettyServer ();
        nettyServer.start();
        log.info("======服務(wù)已經(jīng)啟動========");
    }
}

客戶端部分

NettyClientUtil.java:NettyClient工具類

/**
* Netty客戶端
**/
@Slf4j
public class NettyClientUtil {
    public static ResponseResult helloNetty(String msg) {
        NettyClientHandler nettyClientHandler = new NettyClientHandler();
        EventLoopGroup group = new NioEventLoopGroup();
        Bootstrap bootstrap = new Bootstrap()
                .group(group)
                //該參數(shù)的作用就是禁止使用Nagle算法,使用于小數(shù)據(jù)即時傳輸
                .option(ChannelOption.TCP_NODELAY, true)
                .channel(NioSocketChannel.class)
                .handler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel socketChannel) throws Exception {
                        socketChannel.pipeline().addLast("decoder", new StringDecoder());
                        socketChannel.pipeline().addLast("encoder", new StringEncoder());
                        socketChannel.pipeline().addLast(nettyClientHandler);
                    }
                });
        try {
            ChannelFuture future = bootstrap.connect("127.0.0.1", 8082).sync();
            log.info("客戶端發(fā)送成功....");
            //發(fā)送消息
            future.channel().writeAndFlush(msg);
            // 等待連接被關(guān)閉
            future.channel().closeFuture().sync();
            return nettyClientHandler.getResponseResult();
        } catch (Exception e) {
            log.error("客戶端Netty失敗", e);
            throw new BusinessException(CouponTypeEnum.OPERATE_ERROR);
        } finally {
            //以一種優(yōu)雅的方式進(jìn)行線程退出
            group.shutdownGracefully();
        }
    }
}

NettyClientHandler.java:客戶端處理器

/**
* 客戶端處理器
**/
@Slf4j
@Setter
@Getter
public class NettyClientHandler extends ChannelInboundHandlerAdapter {
    private ResponseResult responseResult;
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        log.info("客戶端Active .....");
    }
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        log.info("客戶端收到消息: {}", msg.toString());
        this.responseResult = ResponseResult.success(msg.toString(), CouponTypeEnum.OPERATE_SUCCESS.getCouponTypeDesc());
        ctx.close();
    }
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        ctx.close();
    }
}

驗(yàn)證

測試接口

@RestController
@Slf4j
public class UserController {
    @PostMapping("/helloNetty")
    @MethodLogPrint
    public ResponseResult helloNetty(@RequestParam String msg) {
        return NettyClientUtil.helloNetty(msg);
    }
}

訪問測試接口

服務(wù)端打印信息

客戶端打印信息

到此這篇關(guān)于SpringBoot項目中使用Netty實(shí)現(xiàn)遠(yuǎn)程調(diào)用的示例代碼的文章就介紹到這了,更多相關(guān)SpringBoot Netty遠(yuǎn)程調(diào)用內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java代碼讀取properties配置文件的示例代碼

    Java代碼讀取properties配置文件的示例代碼

    這篇文章主要介紹了Java代碼讀取properties配置文件,本文通過示例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-05-05
  • 在IDEA中實(shí)現(xiàn)同時運(yùn)行2個相同的java程序

    在IDEA中實(shí)現(xiàn)同時運(yùn)行2個相同的java程序

    這篇文章主要介紹了在IDEA中實(shí)現(xiàn)同時運(yùn)行2個相同的java程序,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-02-02
  • 深入了解Java接口回調(diào)機(jī)制

    深入了解Java接口回調(diào)機(jī)制

    這篇文章主要介紹了Java接口回調(diào)機(jī)制,下面我們來一起學(xué)習(xí)一下吧
    2019-05-05
  • Java出現(xiàn)中文亂碼問題分析及解決方案

    Java出現(xiàn)中文亂碼問題分析及解決方案

    在Java開發(fā)中,處理中文亂碼是一個常見的問題,由于字符集和編碼的復(fù)雜性,開發(fā)者可能面臨各種導(dǎo)致亂碼的情況,正確地處理中文字符集對于確保應(yīng)用程序的可靠性和國際化至關(guān)重要,本文給大家介紹了Java中文亂碼分析及解決方案,需要的朋友可以參考下
    2024-02-02
  • Java中初始化List集合的八種方式匯總

    Java中初始化List集合的八種方式匯總

    List?是?Java?開發(fā)中經(jīng)常會使用的集合,下面這篇文章主要給大家介紹了關(guān)于Java中初始化List集合的八種方式,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-06-06
  • Spring系列之事物管理

    Spring系列之事物管理

    這篇文章主要介紹了Spring系列之事物管理,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用spring方面知識具有一定的參考學(xué)習(xí)價值,需要的朋友們一起學(xué)習(xí)學(xué)習(xí)吧
    2021-09-09
  • MyBatis 使用權(quán)威指南

    MyBatis 使用權(quán)威指南

    MyBatis 是支持定制化 SQL、存儲過程以及高級映射的優(yōu)秀的持久層框架。MyBatis 避免了幾乎所有的 JDBC 代碼和手動設(shè)置參數(shù)以及獲取結(jié)果集,本文給大家介紹MyBatis 使用指南,一起看看吧
    2017-03-03
  • JavaWeb中導(dǎo)出excel文件的簡單方法

    JavaWeb中導(dǎo)出excel文件的簡單方法

    下面小編就為大家?guī)硪黄狫avaWeb中導(dǎo)出excel文件的簡單方法。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-10-10
  • 提示:Decompiled.class file,bytecode version如何解決

    提示:Decompiled.class file,bytecode version如何解決

    在處理Decompiled.classfile和bytecodeversion問題時,通過修改Maven配置文件,添加阿里云鏡像并去掉默認(rèn)鏡像,解決了下載源的問題,同時,檢查并修改了依賴版本,確保了問題的解決
    2024-12-12
  • Java多線程CyclicBarrier的實(shí)現(xiàn)代碼

    Java多線程CyclicBarrier的實(shí)現(xiàn)代碼

    CyclicBarrier可以使一定數(shù)量的線程反復(fù)地在柵欄位置處匯集,本文通過實(shí)例代碼介紹下Java多線程CyclicBarrier的相關(guān)知識,感興趣的朋友一起看看吧
    2022-02-02

最新評論