幼儿饰品瑜伽美体用品微软
投稿投诉
微软创意
爱情通信
用品婚姻
爱好看病
美体软件
影音星座
瑜伽周边
星座办公
饰品塑形
搞笑减肥
幼儿两性
智家潮品

一篇文章玩转RPC通信原理,并使用Netty实现一个PRC(

  1。什么是RPC
  RPC一般指远程过程调用。RPC是远程过程调用(RemoteProcedureCall)的缩写形式。首先看下服务的演变过程:单一应用架构MVC三层架构PRC分布式服务弹性计算架构
  接口请求也在慢慢演变:TCPIP报文协议RMI(仅JAVA可用)WebServiceHTTPGPRC(Thrift,Dubbo)SpringRestful(路径风格)
  总体而言就是随着服务的增多,也伴随着服务之间的调用频繁和繁琐,这就有了PRC这代名词。
  PRC普通应用在分布式架构中,先看下分布式服务派系阿里系:dubbozookeepernginxspring生态:cloudeurekagateway
  RPC的核心职能,以dubbo图解为例
  这个机制现在用的很广泛了,例如cloud中的注册中心和配置中心。大概了解一下理论后,接下来我们用代码来实操,以便更深入的认识PRC。2。Netty实现一个RPC2。1原理概述客户端1。通过bean的初始化回调判断是否需要注入动态代理2。在动态代理回调类中使用Netty调用远程服务,并发送约定协议的消息3。使用回调机制返回服务端响应,并返回原始类服务端1。在bean的回调判断是否为发布的服务,是的话保存在公共map中,初始化时启动Rpc服务2。调用服务解析消息后,通过请求的service获取指定的service,通过反射调用,并将结果返回2。2pom。xml依赖
  基于springboot2。5。6版本,额外引入lombok和fastjsonnetty依赖dependencygroupIdio。nettygroupIdnettyallartifactIdversion4。1。42。Finalversiondependency2。3apijar包
  自定义注解,api目录为待发布的API接口,protocol为公用的协议和工具包
  2。4。客户端架构2。4。1rpc目录下为公用代码,可以单独抽离的
  2。4。2Controller代码注意这两个声明,并没有加Autowired或ResourceRpcReferenceHellServicehellService;RpcReferenceOrderServiceorderService;GetMapping(hello)publicStringhello(RequestParamStringorderId){returnorderService。getOrder(orderId);}GetMapping(add)publicintadd(RequestParamIntegera,RequestParamIntegerb){returnhellService。add(a,b);}
  PS说明:上面的两个声明没有加Autowired或Resource,所以spring容器在注入的时候不会处理这里两个,本文使用的是反射注入。如果想交由spring处理可以参考mybatis第九话手写实现一个简单的mybatis版本中的Mapper接口注入原理2。4。3核心动态代理处理类RpcBeanPostProcessor实现环境配置回调EnvironmentAware该类为初始化类之后的回调还没到注入阶段因此在这里接收环境的回调,读取RPC的配置传递到代理类中Environmentenvironment;注册之前设置坏境变量OverridepublicvoidsetEnvironment(Environmentenvironment){this。environmentenvironment;}实现了InstantiationAwareBeanPostProcessor接口,重写postProcessAfterInitialization方法可以在bean初始化之前后返回继承类或者代理类,aop就是典型的例子OverridepublicObjectpostProcessAfterInitialization(Objectbean,StringbeanName)throwsBeansException{Classlt;?clazzbean。getClass();遍历所有的声明for(Fieldfield:clazz。getDeclaredFields()){如果包含这个注解就创建代理类,并用反射注入if(field。isAnnotationPresent(RpcReference。class)){Objectinstance;StringbeanClassNamefield。getType()。getName();try{单例缓存if(cacheProxyMap。containsKey(beanClassName)){instancecacheProxyMap。get(beanClassName);}else{根据不同的服务名称参数传递不同的rpc调用地址RpcReferenceannotationfield。getAnnotation(RpcReference。class);生成动态代理instanceProxy。newProxyInstance(field。getType()。getClassLoader(),newClass〔〕{field。getType()},可以配置注解参数以获取不同的RPC连接配置newProxyHandler(bean,beanClassName,this。environment。getProperty(annotation。name()。rpcHost),Integer。valueOf(this。environment。getProperty(annotation。name()。rpcPort))));}log。info(createproxybean:{},beanClassName);反射注入field。setAccessible(true);field。set(bean,instance);cacheProxyMap。put(field。getType()。getName(),instance);}catch(IllegalAccessExceptione){log。error(createbeanerror,beanClassName{},beanClassName);}}}returnbean;}2。4。4动态代理调用类ProxyHandlerinvoke方法OverridepublicObjectinvoke(Objectproxy,Methodmethod,Object〔〕args)throwsThrowable{组装协议RpcRequestrequestnewRpcRequest();设置一个唯一ID,用来回调request。setReqId(UUID。randomUUID()。toString());request。setService(this。service);request。setMethod(method。getName());request。setParamterType(method。getParameterTypes());request。setArgs(args);发起服务调用NettyClientnettyClientnewNettyClient();nettyClient。start(rpcHost,rpcPort,newMyRpcClientHandler());返回结果returnnettyClient。sendRequest(request);}2。4。5NettyClient公共类该类不是单例的,但是保存通道和回调的Map是单例的publicChannelchannel;publicvoidstart(Stringhost,intport,RpcHandlerrpcHandler){StringmapKeyhost:port;if(NettyConstans。clientMap。containsKey(mapKey)){this。channelNettyConstans。clientMap。get(mapKey);return;}NioEventLoopGroupb1newNioEventLoopGroup();BootstrapbsnewBootstrap()。group(b1)。channel(NioSocketChannel。class)。handler(newChannelInitializerChannel(){OverrideprotectedvoidinitChannel(Channelchannel)throwsException{ChannelPipelinepipelinechannel。pipeline();这里偷懒就直接用string的编解码了pipeline。addLast(newStringEncoder());pipeline。addLast(newStringDecoder());pipeline。addLast(rpcHandler);}});try{客户端连接服务端ChannelFuturefuturebs。connect(host,port)。sync();future。addListener(listen{if(listen。isSuccess()){log。info(connectrpcservicesuccess,{}:{},host,port);}});channelfuture。channel();保存为单例NettyConstans。clientMap。put(mapKey,channel);}catch(Exceptione){b1。shutdownGracefully();log。error(connectrpcserviceerror,{}:{},host,port);}}publicObjectsendRequest(RpcRequestrpcRequest)throwsException{自定义一个返回结果的回调保存到单例Map中RpcFutureRpcResponserpcFuturenewRpcFuture(newDefaultPromiseRpcResponse(newDefaultEventLoop()));NettyConstans。rpcFutureMap。put(rpcRequest。getReqId(),rpcFuture);消息发送,编解码为string,所以发送的是stringchannel。writeAndFlush(JSONObject。toJSONString(rpcRequest));实际上为阻塞等待回调由接收消息那里回调其实还有一个熔断线程处理这些超时或者一直没有回调的returnrpcFuture。getPromise()。get()。getContent();}2。4。6客户端接收消息handlerMyRpcClientHandler协议RpcResponseOverrideprotectedvoidchannelRead0(ChannelHandlerContextctx,Stringmsg)throwsException{log。info(RpcResponsereceivemsg:{},msg);RpcResponseresponseJSONObject。parseObject(msg,RpcResponse。class);未知的消息直接忽略if(responsenull!NettyConstans。rpcFutureMap。containsKey(response。getReqId()))return;给指定的ReqId回调NettyConstans。rpcFutureMap。get(response。getReqId())。getPromise()。setSuccess(response);NettyConstans。rpcFutureMap。remove(response。getReqId());}OverridepublicvoidexceptionCaught(ChannelHandlerContextctx,Throwablecause)throwsException{log。error(连接出现异常,重置连接:{},ctx。channel()。remoteAddress());异常重连服务端重启之类的NettyConstans。clientMap。remove(ctx。channel()。remoteAddress()。toString());}
  客户端的代码基本上贴完了,比较复杂,服务端会比较简单,接下来看看服务端的代码2。5服务端架构2。5。2。1bean的初始化回调RpcBeanPostProcessorstaticMapString,ObjectbeanMapnewConcurrentHashMap();OverridepublicObjectpostProcessAfterInitialization(Objectbean,StringbeanName)throwsBeansException{Classlt;?clazzbean。getClass();只要包含该注解的就报保存到Map中if(clazz。isAnnotationPresent(RpcService。class)){存的是服务发布的接口类名称beanMap。put(clazz。getInterfaces()〔0〕。getName(),bean);log。info(registerrpcservice:{},clazz。getInterfaces()〔0〕。getName());}returnbean;}
  这里没有往注册中心上发布了,直接以本地Map的形式保存的。主要是为弄懂原理2。5。2NettyService初始化使用springboot的启动回调开始一个RPC服务Overridepublicvoidrun(String。。。args)throwsException{启动代码就不贴了编解码为StringNettyService。start(port,newMyRpcHandler());}自定义handler类MyRpcHandler协议RpcRequestOverrideprotectedvoidchannelRead0(ChannelHandlerContextctx,Stringmsg)throwsException{log。info(RpcRequestreceivemsg:{},msg);RpcRequestrequestJSONObject。parseObject(msg,RpcRequest。class);if(requestnullrequest。getReqId()null)return;Stringservicerequest。getService();ObjectbeanRpcBeanPostProcessor。beanMap。get(service);根据方法名称和参数类型获取类中的方法Methodmethodbean。getClass()。getMethod(request。getMethod(),request。getParamterType());Objectresultmethod。invoke(bean,request。getArgs());响应协议RpcResponseresponsenewRpcResponse();response。setReqId(request。getReqId());response。setContent(result);写出和发送同理ctx。writeAndFlush(JSONObject。toJSONString(response));}3。RPC测试
  分别启动客户端和服务端3。1客户端调用控制台日志createproxybean:com。exmaple。demo。api。HellServicecreateproxybean:com。exmaple。demo。api。OrderService执行http:127。0。0。1:8080hello?orderId1234567connectrpcservicesuccess,127。0。0。1:18080RpcResponsereceivemsg:{content:selectorderservicebyorderId:1234567,reqId:61a37ef56a974fe79ba9d8c3a955c8c0}3。2服务端调用日志startremoteservice:18080RpcRequestreceivemsg:{args:〔1234567〕,method:getOrder,paramterType:〔java。lang。String〕,reqId:61a37ef56a974fe79ba9d8c3a955c8c0,service:com。exmaple。demo。api。OrderService}第二次调用http:127。0。0。1:8080add?a4545b12ahrefhttps:www。bs178。comrizhitargetblankclassinfotextkey日志aRpcRequestreceivemsg:{args:〔4545,12〕,method:add,paramterType:〔int,int〕,reqId:4f312678b4634db9a861d8b4b9c9fc4a,service:com。exmaple。demo。api。HellService}4。总结4。1关于反射注入
  正常应该使用的是FactoryBean的方式注入的,这里只是为了搞懂原理,忽略!4。2关于Rpc服务地址
  正常的RPC服务,会先从注册中心获取这个服务发布的地址,也就是我们配置中的地址实际上是注册中心的地址建立连接后,应该会保持心跳,第二次调用不再重新建立连接4。3关于阻塞异步回调
  实际上还有熔断机制,应该处理掉一直等待的回调

那些回忆机自己曾经喜欢过的一些手机前段时间最好的朋友结婚了,回想以前一起聊手机日子,感叹时间过的很快,所以突然想写一篇于关于自己曾经喜欢过的一些手机以及它们故事的文章,来纪念那些回忆机(集)。还在小学的时……揭秘玩游戏升级送红包的骗局相信大家和我一样为了玩金币和红包活动没少看广告吧,还有其他软件也有这种类似的广告,多不胜数。而最多的就是这种玩游戏升级送红包之类的广告,我也是天天刷到这种广告。刚开始我也是不信……灵耀x凌峰,帮你做更好的自己在高频使用笔记本电脑的当下,轻便高效已然成为众多商务人士选购笔记本的首要考虑条件。对比市面上各种型号的笔记本,主流的14英寸商务轻薄本的重量都在1。4kg左右,同样尺寸下,不足……一边打东决,一边拿状元见证凯尔特人的崛起之路一边打东决,一边拿状元,从选秀权见证凯尔特人是怎样一步一步崛起的。2013年凯尔特人把日薄西山的加内特和皮尔斯交易到篮网。得到篮网的2014年、2016年、2018……2022年换机,预算3000块选哪些手机?这几款闭眼买不出错2022年买手机,预算3000块选哪些手机?这几款闭眼买不出错第一款:红米K50Pro处理器:天玑9000屏幕:6。67英寸,AMOLED,120Hz刷新影像:1。08亿主摄8……真就那么解压,休闲游戏冲就完事模拟器,和所有的烦恼说拜拜冲指的是用高压水枪冲洗污渍,并非其他特殊的含义。玩蛋今天向大家分享的是一款非常解压的休闲游戏《冲就完事模拟器》,目前该游戏在steam平台获得2万多条留言,超过97的好评,斩获……狂肝10个月手搓GPU,他们在我的世界中玩起我的世界,梦想成梦晨衡宇萧箫发自凹非寺量子位公众号QbitAI自从有人在《我的世界》里用红石电路造出CPU,就流传着一个梗:总有一天,这帮红石佬能在我的世界里玩上我的世界。……太阳注定无冠?太阳队打出湖人王朝数据,正好湖人2次失冠太阳本赛季能不能夺冠?虽然在G3独行侠暴打太阳,但他们仍然创下了一项NBA历史纪录!面对独行侠G3的悲惨绝境正如东契奇对克里斯保罗的公然嘲讽:什么控卫之神?假摔之神吧!……北京烧烤溜娃好去处!天气刚好,你带着娃,我带着烧烤春夏之交,又到了室外露营烧烤的好时节!趁着假期,约上三五好友,带着娃,伴着蓝天白云,微微的暖风,坐在河边亦或是绿荫下,支起烧烤,大快朵颐,生活就是如此美好!小编推荐几个可以烧烤……大师巡回赛纳斯利亚堡的悬案站落幕Tansoku夺冠大师巡回赛在本周末的纳斯利亚堡迎来了新的历史,亚太炉石终于在巡回赛舞台上来了一次强势崛起,成功实现了零的突破。在此之前,亚太选手的巡回赛最好成绩是日本选手Alutemu的两次亚……今年五一变了,年轻人不再爬山涉水,唯品会一组数据印证变化这个五一假期,不是在露营,就是在露营的路上。一位网友笑称道。如果要说今年五一假期最火热的活动,露营绝对位列其中,像游泳、滑冰、摘樱桃等活动都得给大热的露营让道。有人带上锅……有情调的度假生活,留下精彩的回忆,延庆玉渡山悦庭杏舍民宿玉渡山悦庭杏舍民宿,小院坐落在海坨山脚下,和玉渡山景区只有直尺之遥,小院周边有古崖居,龙庆峡等景区,看烟烟的山,潺潺的水,这风里都藏着慵懒的气息呢!民宿很适合聚餐,还可以……
天仙刘亦菲主演的梦华录你看到了什么一部好剧,需要编剧精雕细琢地打磨剧本;一部好剧,需要导演不惧辛苦地进行拍摄;一部好剧,需要演员尽心尽力地演绎在我所有看的影视剧当中,我最喜欢的影视剧莫属于今年暑假大爆的《梦华录……对阵世界强队,勇夺亚军!这支中国荷球队由郑州大学师生领衔,将日前,2022年亚洲大洋洲荷球锦标赛在泰国芭提雅市举行。由郑州大学师生组成的中国荷球队参加比赛,并荣获亚军。由郑州大学师生领衔的中国荷球队荣获2022年亚洲大洋洲荷球锦标……抗病毒领域医药股持续活跃,传递出市场复苏信号(人民日报健康客户端记者张赫实习记者侯佳欣)近日,随着一系列优化疫情防控措施的出台,旅游、航空、酒店等行业复苏趋势明显。航空、旅游、餐饮等板块最近出现较大幅度的上涨,主要……星空比之前预期的规模更大更雄心勃勃近日XNC播客中主持人ColtEastwood提到,他从据说测试过《星空》的人那听说,B社旗下大作《星空》比之前预期规模更大,更加雄心勃勃。据悉,《星空》比在《上古卷轴5……先有特斯拉,后有蔚来,智能车机时代的怎么逃避数据泄露?车主个人信息泄露,蔚来汽车遭遇黑客勒索。12月20日,蔚来汽车高管和创始人连续自曝,称大量车主信息泄露,遭遇邮件勒索1570万元。目前,已经有不少蔚来车主接到骚扰电话,蔚来汽车……21!罗马终结2连败,攀升联赛第5位,迪巴拉传射建功,佩7丢今天凌晨,意甲联赛第6轮最后一场比赛结束,罗马队客场21击败恩波利,结束了各项赛事2连败。本场比赛,迪巴拉大放异彩,他传射建功,还有一次击中立柱,亚伯拉罕打进制胜球,佩莱格里尼……以为自己夺冠披上国旗!奥运赛场乌龙事件,黑人选手质疑中国冠军中国田径在奥运会的赛场上曾经给大家带来过非常多精彩的瞬间,比如,刘翔的110米栏、苏炳添的百米飞人大战,都是粉丝印象中的经典场面。其实除了这些短道项目以外,在长跑项目上中国田径……适合秋天吃的8道菜,营养又补钙,鲜香味美,老少皆宜,安稳入秋大家好!今天小主推荐几道适合在秋季吃的菜单,每一道都营养又补钙,鲜香味美,大人小孩都喜欢的,如果喜欢的就快尝试煮几道给家人吃吃啦!他们都会给你一个大拇指的!一、《红烧鱼块……48110000000次播放!背后是28天,64场比赛,联结着不同地域、不同肤色、不同时区的50亿心跳。球场上,助攻、传射、绝杀,反转不断。手机前,科技观赛、云上侃球,令人耳目一新。这届世界杯,视频云技术改……人生如茶(393)作者:刘峙锋教养是人的行为方式是文化和品德修养源于社会影响源于家庭教育源于学校教育源于个人修养教养是配位的品德是立世……95花中黑马曾被九所学校录取,周迅把她当接班人培养《点燃我,温暖你》宣布完结,这部从开始就备受关注的作品。在大众评分上,轻轻松松拿下了7。4分的好成绩。这样的好成绩,是男女主共同努力的结果。剧中的男主演陈飞宇……程序员夏天穿格子衫,冬天穿什么?答案扎心了哈哈哈哈哈在穿搭界有一群神一般的人物存在他们永远可以把月薪三万的自己穿出月薪三千的既视感来这类人群就是程序员程序员的穿衣风格经常被关注因为他们钟爱各种……
友情链接:易事利快生活快传网聚热点七猫云快好知快百科中准网快好找文好找中准网快软网