netty系列文章:

01-netty基础-socket
02-netty基础-java四种IO模型
03-netty基础-多路复用select、poll、epoll
04-netty基础-Reactor三种模型
05-netty基础-ByteBuf数据结构
06-netty基础-编码解码
07-netty基础-自定义编解码器
08-netty基础-自定义序列化和反序列化
09-netty基础-手写rpc-原理-01
10-netty基础-手写rpc-定义协议头-02
11-netty基础-手写rpc-支持多序列化协议-03
12-netty基础-手写rpc-编解码-04
13-netty基础-手写rpc-消费方生成代理-05
14-netty基础-手写rpc-提供方(服务端)-06

1 功能逻辑

在服务端启动的时候,在spring容器中bean已经被初始化好之后,拿到当前bean的信息,判断是否被BonnieRemoteService修饰,如果被修饰则获取到当前类下的所有Method,然后将这个Method信息缓存到容器中。以供后续rpc反射调用。
缓存容器使用Map, key:类的全路径+方法名称  value:Method即可

2、核心代码

spring容器中bean已经被初始化好,可以实现BeanPostProcessor接口中的postProcessAfterInitialization方法实现初始化后扩展功能

实现InitializingBean接口中afterPropertiesSet方法,将nettyServer的服务放在这块启动

2.1 收集BonnieRemoteService修饰的类

package com.bonnie.protocol.spring.service;import com.bonnie.protocol.annotation.BonnieRemoteService;
import com.bonnie.protocol.netty.NettyServer;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;import java.lang.reflect.Method;@Component
@Slf4j
public class SpringRpcProviderBean implements BeanPostProcessor, InitializingBean {private String serverAddress = "127.0.0.1";private Integer serverPort = 48081;//    public SpringRpcProviderBean(String serverAddress, Integer serverPort) {
//        this.serverAddress = serverAddress;
//        this.serverPort = serverPort;
//    }/*** bean初始化完成后,执行该逻辑* @param bean* @param beanName* @return* @throws BeansException*/@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {System.out.println("SpringRpcProviderBean===="+beanName);// 只要bean声明了BonnieRemoteService注解,则需要把该服务发布到网络上// 判断当前类上是否有注解BonnieRemoteServiceboolean flag = bean.getClass().isAnnotationPresent(BonnieRemoteService.class);if (flag) {Method[] declaredMethods = bean.getClass().getDeclaredMethods();for (Method method : declaredMethods) {String serviceName = bean.getClass().getInterfaces()[0].getName();String key = serviceName + "." + method.getName();BeanMethod beanMethod = new BeanMethod();beanMethod.setBean(bean);beanMethod.setMethod(method);// 缓存到map容器中Mediator.beanMethodMap.put(key, beanMethod);}}return bean;}@Overridepublic void afterPropertiesSet() throws Exception {log.info("启动Netty服务端======48081");new Thread(()->{new NettyServer(serverAddress, serverPort).startNettyServer();}).start();}
}

2.2 NettyServer实现

启动服务,设置编解码的方式

package com.bonnie.protocol.netty;import com.bonnie.protocol.code.BonnieDecoder;
import com.bonnie.protocol.code.BonnieEncoder;
import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import lombok.extern.slf4j.Slf4j;@Slf4j
public class NettyServer {private String serverAddress;private Integer serverPort;public NettyServer(String serverAddress, Integer serverPort) {this.serverAddress = serverAddress;this.serverPort = serverPort;}public void startNettyServer() {log.info("begin start Netty server");NioEventLoopGroup boss = new NioEventLoopGroup();NioEventLoopGroup work = new NioEventLoopGroup();ServerBootstrap serverBootstrap = new ServerBootstrap();serverBootstrap.group(boss, work).channel(NioServerSocketChannel.class).childHandler(new ChannelInitializer<SocketChannel>() {@Overrideprotected void initChannel(SocketChannel ch) throws Exception {ch.pipeline()// 长度域解码器.addLast(new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 12, 4, 0, 0)).addLast(new BonnieEncoder()).addLast(new BonnieDecoder()).addLast(new RpcServerHandler());}});try {ChannelFuture channelFuture = serverBootstrap.bind(this.serverAddress, this.serverPort).sync();log.info("Server started Success on serverAddress {} Port,{}",this.serverAddress, this.serverPort);channelFuture.channel().closeFuture().sync();} catch (InterruptedException e) {e.printStackTrace();} finally {boss.shutdownGracefully();work.shutdownGracefully();}}}

2.3 NettyServer接收客户端请求数据

package com.bonnie.protocol.netty;import com.alibaba.fastjson.JSONObject;
import com.bonnie.protocol.core.Header;
import com.bonnie.protocol.core.RpcProtocol;
import com.bonnie.protocol.core.RpcRequest;
import com.bonnie.protocol.core.RpcResponse;
import com.bonnie.protocol.enums.ReqTypeEnum;
import com.bonnie.protocol.spring.service.Mediator;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;public class RpcServerHandler extends SimpleChannelInboundHandler<RpcProtocol<RpcRequest>> {private static final Logger log = LoggerFactory.getLogger(RpcServerHandler.class);/*** 服务端接收客户端消息* @param ctx* @param msg* @throws Exception*/@Overrideprotected void channelRead0(ChannelHandlerContext ctx, RpcProtocol<RpcRequest> msg) throws Exception {long requestId = msg.getHeader().getRequestId();log.info("接收到客户端的消息: requestId {} {}", requestId, JSONObject.toJSONString(msg));// 构建返回消息ReqResponseRpcProtocol<RpcResponse> responseRpcProtocol = new RpcProtocol<>();Header header = msg.getHeader();// 设置返回的消息类型header.setReqType(ReqTypeEnum.RESPONSE.getCode());// 通过调用获取到方法的返回数据Object result = Mediator.getInstance().processor(msg.getContent());RpcResponse rpcResponse = new RpcResponse();rpcResponse.setMsg("success");rpcResponse.setData(result);responseRpcProtocol.setHeader(header);responseRpcProtocol.setContent(rpcResponse);// 数据写入到客户端ctx.writeAndFlush(responseRpcProtocol);}}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/pingmian/92259.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/92259.shtml
英文地址,请注明出处:http://en.pswp.cn/pingmian/92259.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

连续时间和数字之间频率的偏差以及相位补偿

接下来需要讲解在连续时间域下的角频率以及在离散化后的数字角频率。上面可以知道模拟角频率和数字的区别 接下来介绍相位 相位单位是弧度无频偏&#xff1a; 对于数字来说是对连续信号采样后的结果&#xff0c;数字的角频率 &#xff0c;就是相位的递增量&#xff0c;表示每个…

《Git从入门到精通:告别版本管理混乱》

坚持用 清晰易懂的图解 代码语言&#xff0c;让每个知识点变得简单&#xff01; &#x1f680;呆头个人主页详情 &#x1f331; 呆头个人Gitee代码仓库 &#x1f4cc; 呆头详细专栏系列 座右铭&#xff1a; “不患无位&#xff0c;患所以立。” 《Git从入门到精通&#xff1a…

小红书开源多模态视觉语言模型DOTS-VLM1

项目简介与模型基本介绍 DOTS-VLM1 是由小红书希实验室(Rednote HiLab)开源的多模态视觉语言模型(Vision-Language Model, VLM),旨在推动视觉与语言理解的融合研究。DOTS-VLM1 采用主流的编码-融合-解码架构,支持图片与文本的联合理解与生成,适用于图文问答、图片描述、…

【Git】企业级使用

&#x1f525;个人主页&#xff1a; 中草药 &#x1f525;专栏&#xff1a;【中间件】企业级中间件剖析 基本概念 Git 有三个核心区域&#xff0c;分别是工作区、暂存区和版本库&#xff0c;理解这三个区域是掌握 Git 的基础。​ ​ 工作区就是我们电脑里能看到的文件目录&…

Druid学习笔记 02、快速使用Druid的SqlParser解析

文章目录前言本章节源码描述认识作者官方文档快速入门demo案例引入依赖获取到SQL的AST(抽象语法树)使用visitor完成表、字段、表达式解析汇总总结一、简介1.1、和Antlr生成Parser的区别1.2、Druid SQL Parser的使用场景二、各种语法支持三、性能四、Druid SQL Parser的代码结构…

时间复杂度计算(以for循环为例)

本文理论内容来自严蔚敏版《数据结构(C语言版 第2版)》 *本文仅为复习时的总结&#xff0c;描述不准确、过程不严谨之处&#xff0c;还请理解 一、算法的相关概念 首先复习一下算法的定义及5个重要特性 其次是算法的评价标准 可以看到 时间复杂度 属于算法评价标准中的高效性…

图论(1):图数据结构

目录 一、图的定义 1.1 图的基本概念 1.2 图的分类 &#xff08;1&#xff09;按边的方向&#xff1a; &#xff08;2&#xff09;按边的权值&#xff1a; &#xff08;3&#xff09;按边的数量和类型&#xff1a; &#xff08;4&#xff09;按连通性&#xff1a; 1.3 图…

等保测评-Nginx中间件

Nginx *排查有无Nginx中间件&#xff0c;可使用以下命令&#xff1a; ps -ef | grep nginx、netstat -nutlp *确认Nginx中间件有运行&#xff0c;查看其目录&#xff1a; find / -name nginx.conf、ps -ef | grep Nginx *确认好目录后&#xff0c;查看版本&#xff1a; …

Milvus向量数据库版本升级

创建时间&#xff1a;2025-3-11 更新时间&#xff1a;2025-8-8 作者&#xff1a;薄刀刀、散装DBA 联系方式&#xff1a;bulkdba&#xff0c;1511777 背景&#xff1a;当前版本无法使用分组搜索功能&#xff0c;通过升级版本解决&#xff0c;计划将milvus升级到2.4.15&#xf…

若依前后端分离版学习笔记(六)——JWT

在上一节已经提到了传统Session认证和JWT认证内容&#xff0c;这一节对JWT进行更加详细的了解。 一 JWT介绍 1、传统的session认证 1.1 传统session认证流程 1.用户向服务器发送用户名和密码 2.服务器通过验证后&#xff0c;在当前对话&#xff08;session&#xff09;中保存相…

如何永久删除三星手机中的照片?

如果你计划出售你的三星 Galaxy 手机&#xff0c;或者整理其接近满容量的存储空间&#xff0c;你可能会担心如何从设备中移除照片和其他文件。这对于确保你的个人信息保持安全至关重要&#xff0c;即使你选择通过各种平台捐赠或出售旧手机也是如此。在本文中&#xff0c;我们介…

【数字图像处理系列笔记】Ch06:图像压缩

一、基础知识信源编码器&#xff1a;减少或消除输入图像中的编码冗余、像素 间冗余以及心理视觉冗余。 数据的冗余 一、空间冗余&#xff08;Spatial Redundancy&#xff09;1. 定义图像中相邻像素间的强相关性导致的冗余 —— 同一区域内相邻像素的像素值&#xff08;如灰度、…

windows线程基础

Windows线程机制详解 线程的基本概念 在Windows操作系统中&#xff0c;线程是程序执行的最小单位。每个进程至少包含一个线程&#xff08;主线程&#xff09;&#xff0c;但可以创建多个线程来并行执行任务。线程与进程的主要区别在于&#xff1a; 资源分配&#xff1a;进程拥有…

Numpy科学计算与数据分析:Numpy随机数生成入门

Numpy随机数生成实战 学习目标 通过本课程&#xff0c;学员将掌握如何使用Numpy库生成不同类型的随机数&#xff0c;包括随机整数、随机浮点数以及从特定分布中抽样的方法。本课程将通过理论讲解与实践操作相结合的方式&#xff0c;帮助学员深入理解Numpy在随机数生成方面的强…

使用 C# 通过 .NET 框架开发应用程序的安装与环境配置

文章目录1. .NET介绍2. IDE2.1 Rider 安装2.2 Visual Studio 安装3. SDK安装与环境配置3.1 单独下载安装 .NET SDK3.2 Visual Studio 工作负荷安装SDK4. 相关问题4.1 我以前使用 Unity 写 C# 脚本不需要额外的编译器&#xff0c;为什么现在需要&#xff1f;1. .NET介绍 .NET 是…

Scikit-learn - 机器学习库初步了解

目录1. 主要算法分类1.1 监督学习 (Supervised Learning)1.2 非监督学习 (Unsupervised Learning)1.3 半监督学习 (Semi-Supervised Learning)1.4 强化学习 (Reinforcement Learning)1.5 遗传算法 (Genetic Algorithm)2. 选择合适的机器学习模型2.1 分类 (Classification)2.2 回…

关于 idea 里 properties 文件的中文乱码问题

背景 你会发现 properties 文件里的中文可能会出现乱码。 这个因为 properties 规范是使用 iso-8859-1 存储的&#xff0c;不支持中文&#xff08;也不支持西欧里法语、德语里奇怪的字母&#xff09; properties 的标准制定于很早&#xff0c;所以没考虑这么多&#xff0c;prop…

BVH文件 解析 解读的python第三方类库 推荐

我们面临多个第三方库选项用于解析BVH文件&#xff0c;根据您的列表&#xff0c;我将分析几个关键库的特点&#xff0c;并推荐最适合当前任务的库。我们将基于以下标准进行选择&#xff1a; ​​功能性​​&#xff1a;是否能准确解析关节角度数据&#xff0c;支持关键帧操作 ​…

uni-app X能成为下一个Flutter吗?

哈喽&#xff0c;我是老刘 老刘使用Flutter作为客户端主要技术栈的这六七年的时间里&#xff0c;关于跨平台开发的争议和新技术始终没有停过。 “一套代码&#xff0c;多端运行”——这个让无数开发者心动的承诺&#xff0c;究竟是技术革命还是美丽的谎言&#xff1f; 想象一…

Spring Cloud Gateway全栈实践:动态路由能力与WebFlux深度整合

一、为什么需要下一代网关&#xff1f; 传统网关的三大瓶颈&#xff1a; #mermaid-svg-Kdei9Io6KntYGQc4 {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-Kdei9Io6KntYGQc4 .error-icon{fill:#552222;}#mermaid-svg-…