使用Springboot整合开发Netty(一个表白的小案例)

简介: 写了很久的java并发包里面的文章,今天换一个口味。很早之前学的Netty,由于最近项目经常使用到,遇到了很多坑,因此想通过一个体系教程说一下这个高性能异步通信框架Netty,这也是netty的第一篇文章。主要是通过Springboot来整合Netty实现一个最基本的案例。

一、Netty是什么


想认识Netty最好的方式就是直接去官网看文档,由于文档是英文,因此直接在这里翻译过来了。


Netty是一个高性能、异步事件驱动的NIO框架,支持如TCP、UDP协议和传输文件。“高性能”并不意味着程序会出现各种性能或其他问题。它是一种精心设计的框架,其灵活性、稳定性依然能够得到保证。

官网说这个Netty特别好,毕竟是自家的产品,不过好不好还是用户说了才可以,通过实践证明,目前Netty是我们业界最流行的NIO框架,无数个商业项目也已经验证了。毕竟java的NIO框架开发起来太恶心,而且还有各种bug没有解决。


为什么我们要首选Netty呢?之前看的书列举了很多条,不过最根本的我觉得还是这几个:使用简单、功能强大、性能高、开发无烦恼。无烦恼是因为bug较少,而且也比较成熟。


相信你看这篇文章,可能是项目中要用到,也可能只是想学习一个新技能。不管是出于什么目的,通过上面的分析,你就会发现这个Netty真的是很有必要了解学习。下面我们就直接上手写个最基本的案例吧。


二、案例实现


这个是一个客户端服务端简单通信的案例,假设服务端是个女孩,客户端男孩向其表白。

男孩:I love you 女孩:no 男孩:不灰心不丧气,继续爱你


1、前提准备


如果你是Springboot直接在maven中添加依赖即可

<!--添加netty依赖-->
<dependency>
       <groupId>io.netty</groupId>
       <artifactId>netty-all</artifactId>
       <version>5.0.0.Alpha1</version>
</dependency>

如果你没有使用maven那么直接去官网或者是百度下载一个netty-all-5.0.0.Alpha1的jar包导入即可。


2、服务端(女孩)开发


我们直接看代码,再来分析其流程。

@Component
public class NettyServer {
    EventLoopGroup boss = new NioEventLoopGroup();
    EventLoopGroup work = new NioEventLoopGroup();
    @PostConstruct
    public void start() throws InterruptedException {
            ServerBootstrap bootstrap = new ServerBootstrap();
            bootstrap.group(boss, work)
                    .channel(NioServerSocketChannel.class)
                    .option(ChannelOption.SO_BACKLOG, 1024)
                    .childOption(ChannelOption.SO_KEEPALIVE, true)
                    .handler(new LoggingHandler(LogLevel.INFO))
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        public void initChannel(SocketChannel sc) throws Exception {
                            sc.pipeline().addLast(new ServerUAVHandler());
                        }
                     });
            ChannelFuture cf = bootstrap.bind(8888).sync();
            if (cf.isSuccess()){
                System.out.println("启动成功");
            }
    }
    @PreDestroy
    private void destory() throws Exception{
        boss.shutdownGracefully();
        work.shutdownGracefully();
        System.out.println("关闭server");
    }
}

基本流程最好对照着代码来看,这样理解的会更加深刻。


(1)new了两个NioEventLoopGroup,一个是boss,一个是work。NioEventLoopGroup是一个线程组,boss线程组用于接收客户端的连接工作,work线程组用于处理数据。


(2)在start方法中,首先new了一个ServerBootstrap,,名字叫bootstrap。它是netty用于启动NIO服务端的辅助启动类。目的是降低服务端的开发复杂度。


(3).group(boss, work)目的是将两个线程组传入,让其工作。


(4).channel(NioServerSocketChannel.class)就类比与NIO中的ServerSocketChannel。


(5).option(ChannelOption.SO_BACKLOG, 1024)配置TCP参数,将其中一个参数backlog设置为1024,表明临时存放已完成三次握手的请求的队列的最大长度。


(6).childOption(ChannelOption.SO_KEEPALIVE, true)设置TCP长连接,一般如果两个小时内没有数据的通信时,TCP会自动发送一个活动探测数据报文。


(7).handler(new LoggingHandler(http://LogLevel.INFO))处理Log日志。


(8).childHandler,用于处理客户端的IO事件,比如有一个客户端发起请求,要读取数据,就可以使用这里面的类来处理这个事件。这是整个处理的核心。也是我们自己主要关注的类。


(9)ChannelFuture cf = bootstrap.bind(8888).sync();绑定监听端口。使用sync方法阻塞一直到绑定成功。


(10)下面通过一个if语句表明,如果绑定成功那就输出“服务端启动成功”。


(11)最后将boss和work使用finally代码块优雅的退出。何为优雅今后再说。

其实上面的这些代码都是固定模式的,也就是说你使用的时候直接就可以用了,最核心的就是如何处理客户端的各种事件,比如说有客户端连接、读、写数据等等相关事件。看看ServerUAVHandler类是如何实现的,


public class ServerUAVHandler extends ChannelHandlerAdapter {
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        ByteBuf buf = (ByteBuf) msg;
        byte[] req = new byte[buf.readableBytes()];
        buf.readBytes(req);
        String body = new String(req,"UTF-8");
        System.out.println("客户端信息是:"+body);
        ByteBuf resp = Unpooled.copiedBuffer("no".getBytes());
        ctx.writeAndFlush(resp).addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
    }
}

基本流程如下:


(1)ServerUAVHandler继承了ChannelHandlerAdapter主要是用于处理网络的读写事件。


(2)重写了channelRead读方法,在这个方法内部可以读取客户端的请求信息。其中一个参数msg就是封装的信息对象。我们可以在内部通过ByteBuf这个工具类进行读取。内部实现的细节就不再多描述了。


3、客户端(男孩)开发


@Component
public class NettyClient {
    private SocketChannel socketChannel;
    EventLoopGroup group = new NioEventLoopGroup();
    @PostConstruct
    public void start() throws Exception {
        //boss 线程组用于处理连接工作
        try{
            Bootstrap b = new Bootstrap();
            b.group(group).channel(NioSocketChannel.class)
                    .option(ChannelOption.TCP_NODELAY, true)
                    .option(ChannelOption.SO_KEEPALIVE,true)
                    .handler(new ChannelInitializer<SocketChannel>() {
                        public void initChannel(SocketChannel ch) throws Exception {
                            ch.pipeline().addLast(new ClientHandler());
                        }
                    });
            //绑定端口
            ChannelFuture cf = b.connect("127.0.0.1",8888).sync();
            if(cf.isSuccess()){
                System.out.println("链接服务器成功");
            }
            cf.channel().closeFuture().sync();
        }finally{
           group.shutdownGracefully();
        }
    }
}

从上面的代码我们会发现,和服务器端的类似,我们在这里主要关注于和服务器有什么不一样,可能是年龄越来越大,你在对比的时候一定要返回去看看,不仅可以加深印象,还可能突然就恍然大悟了。


(1)首先,只new了一个NioEventLoopGroup,因为不需要处理连接,所以客户端只关注于读写数据的操作。


(2)在start方法内部创建了一个Bootstrap,名字是b,意思是客户端的启动类。


(3)接着使用option配置一些参数。


(4)使用handler方法传递一个类,在内部有一个ClientHandler类,同样也是客户端的核心。


(5)接下来链接服务器,指定地址和端口。最终关闭链接优雅的推出线程组。


上面的代码都是模板代码,你可以直接拿来用,在后期越来越深入的时候再来修改。在这里我们还是主要关注一下这个ClientHandler类吧。


public class ClientHandler extends ChannelHandlerAdapter {
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        byte[] req = "I love you".getBytes();
        ByteBuf first = Unpooled.buffer(req.length);
        first.writeBytes(req);
        ctx.writeAndFlush(first).addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
    }
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        ByteBuf buf = (ByteBuf) msg;
        byte[] req = new byte[buf.readableBytes()];
        buf.readBytes(req);
        String body = new String(req,"UTF-8");
        if("no".equals(body)){
            ByteBuf resp = Unpooled.copiedBuffer("不灰心不丧气,继续我爱你".getBytes());
            ctx.writeAndFlush(resp).addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
        }
    }
}

在这里客户端,首先给服务端发送一个消息“I Love you ”。然后如果收到的是no回复,再说一次“不灰心不丧气,继续我爱你”。这里重写了两个方法channelActive和channelRead方法,第一个是连接到服务端的时候调用,一个是读取服务端的信息调用。


三、总结


通过以上的分析,不知道你能否体会到Netty带来的方便,其实NettyServer类和NettyClient都是模板类,我们只需要关注于这个handler处理类即可,而且相关的处理方法,我们可以直接通过重写就可以实现。再回想一下NIO编程客户端和服务端通信的时候,代码写的都想XX。


OK,今天的文章就先说到这里吧,对了学习最好的方式就是动手敲一遍,有时候看着很简单,但是真实的操作一遍就会遇见很多坑。

相关文章
|
10月前
|
XML Java 数据格式
SpringBoot入门(8) - 开发中还有哪些常用注解
SpringBoot入门(8) - 开发中还有哪些常用注解
133 0
|
5月前
|
前端开发 Java 关系型数据库
基于Java+Springboot+Vue开发的鲜花商城管理系统源码+运行
基于Java+Springboot+Vue开发的鲜花商城管理系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Java编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Java的鲜花商城管理系统项目,大学生可以在实践中学习和提升自己的能力,为以后的职业发展打下坚实基础。技术学习共同进步
420 7
|
5月前
|
人工智能 Java 数据库
飞算 JavaAI:革新电商订单系统 Spring Boot 微服务开发
在电商订单系统开发中,传统方式耗时约30天,需应对复杂代码、调试与测试。飞算JavaAI作为一款AI代码生成工具,专注于简化Spring Boot微服务开发。它能根据业务需求自动生成RESTful API、数据库交互及事务管理代码,将开发时间缩短至1小时,效率提升80%。通过减少样板代码编写,提供规范且准确的代码,飞算JavaAI显著降低了开发成本,为软件开发带来革新动力。
|
6月前
|
缓存 NoSQL Java
基于SpringBoot的Redis开发实战教程
Redis在Spring Boot中的应用非常广泛,其高性能和灵活性使其成为构建高效分布式系统的理想选择。通过深入理解本文的内容,您可以更好地利用Redis的特性,为应用程序提供高效的缓存和消息处理能力。
517 79
|
3月前
|
网络协议 Java
在SpringBoot项目中使用Netty实现远程调用
本文介绍了使用Netty解决网络连接性能问题的方法,重点讲解了Netty的NIO特性及其在SpringBoot中的应用。Netty作为高效的NIO框架,支持非阻塞IO,能通过单线程管理多个客户端连接,简化TCP/UDP套接字服务器开发。文章详细展示了Netty在SpringBoot中实现远程调用的过程,包括服务端与客户端代码实现、依赖配置及测试验证。通过示例代码,如`NettyServer`、`NettyClientUtil`等,清晰说明了Netty的工作原理和实际应用,解决了半包等问题,并提供了完整的测试结果。
503 3
|
4月前
|
供应链 JavaScript BI
ERP系统源码,基于SpringBoot+Vue+ElementUI+UniAPP开发
这是一款专为小微企业打造的 SaaS ERP 管理系统,基于 SpringBoot+Vue+ElementUI+UniAPP 技术栈开发,帮助企业轻松上云。系统覆盖进销存、采购、销售、生产、财务、品质、OA 办公及 CRM 等核心功能,业务流程清晰且操作简便。支持二次开发与商用,提供自定义界面、审批流配置及灵活报表设计,助力企业高效管理与数字化转型。
446 2
ERP系统源码,基于SpringBoot+Vue+ElementUI+UniAPP开发
|
3月前
|
Java API 微服务
Java 21 与 Spring Boot 3.2 微服务开发从入门到精通实操指南
《Java 21与Spring Boot 3.2微服务开发实践》摘要: 本文基于Java 21和Spring Boot 3.2最新特性,通过完整代码示例展示了微服务开发全流程。主要内容包括:1) 使用Spring Initializr初始化项目,集成Web、JPA、H2等组件;2) 配置虚拟线程支持高并发;3) 采用记录类优化DTO设计;4) 实现JPA Repository与Stream API数据访问;5) 服务层整合虚拟线程异步处理和结构化并发;6) 构建RESTful API并使用Springdoc生成文档。文中特别演示了虚拟线程配置(@Async)和StructuredTaskSco
386 0
|
11月前
|
开发框架 前端开发 网络协议
Spring Boot结合Netty和WebSocket,实现后台向前端实时推送信息
【10月更文挑战第18天】 在现代互联网应用中,实时通信变得越来越重要。WebSocket作为一种在单个TCP连接上进行全双工通信的协议,为客户端和服务器之间的实时数据传输提供了一种高效的解决方案。Netty作为一个高性能、事件驱动的NIO框架,它基于Java NIO实现了异步和事件驱动的网络应用程序。Spring Boot是一个基于Spring框架的微服务开发框架,它提供了许多开箱即用的功能和简化配置的机制。本文将详细介绍如何使用Spring Boot集成Netty和WebSocket,实现后台向前端推送信息的功能。
2612 1
|
6月前
|
人工智能 自然语言处理 前端开发
20分钟上手DeepSeek开发:SpringBoot + Vue2快速构建AI对话系统
本文介绍如何使用Spring Boot3与Vue2快速构建基于DeepSeek的AI对话系统。系统具备实时流式交互、Markdown内容渲染、前端安全防护等功能,采用响应式架构提升性能。后端以Spring Boot为核心,结合WebFlux和Lombok开发;前端使用Vue2配合WebSocket实现双向通信,并通过DOMPurify保障安全性。项目支持中文语义优化,API延迟低,成本可控,适合个人及企业应用。跟随教程,轻松开启AI应用开发之旅!
|
8月前
|
监控 Java 应用服务中间件
SpringBoot是如何简化Spring开发的,以及SpringBoot的特性以及源码分析
Spring Boot 通过简化配置、自动配置和嵌入式服务器等特性,大大简化了 Spring 应用的开发过程。它通过提供一系列 `starter` 依赖和开箱即用的默认配置,使开发者能够更专注于业务逻辑而非繁琐的配置。Spring Boot 的自动配置机制和强大的 Actuator 功能进一步提升了开发效率和应用的可维护性。通过对其源码的分析,可以更深入地理解其内部工作机制,从而更好地利用其特性进行开发。
279 6