基于动态代理的WebAPI/RPC/webSocket框架,一套接口定义,多个通讯方式
API/RPC/webSocket三个看起来好像没啥相同的地方,在开发时,服务端,客户端实现代码也大不一样
最近整理了一下,通过动态代理的形式,整合了这些开发,都通过统一的接口约束,服务端实现和客户端调用
基于这样的形式,WebAPI/RPC/webSocket只需要定义一套接口,就能达到通用的效果
示例接口约束
public class TestObj
{
public string Name { get; set; }
}
public interface ITestService
{
void Login();
bool Test1(int a,int? b,out string error);
TestObj Test2(TestObj obj);
}
public class TestService : AbsService, ITestService
{
[LoginPoint]
public void Login()
{
SaveSession("hubro", "", "test");
} public bool Test1(int a, int? b, out string error)
{
var user = CurrentUserName;
var tag = CurrentUserTag; error = "out error";
Console.WriteLine(a);
Console.WriteLine(b);
return true;
} public TestObj Test2(TestObj obj)
{
Console.WriteLine(obj.ToJson());
return obj;
}
}
上面是一个标准接口和接口实现,并继承了AbsService,
Login方法标注了LoginPoint特性,表示登录切入点,调用此接口时首先得调用此方法,方法内SaveSession存储登录状态
Test1方法内使用了CurrentUserName,以获取登录方法保存的Session
特点:
- 通过接口约束服务端和客户端调用,参数定义透明化,out也支持
- 真正的方法远程调用,任意参数类型,个数
- 集成登录认证逻辑,自定义登录认证过程,也可以自定义Session实现
- 集成简单数据签名,不用费心数据安全问题
技术实现:
- Dynamitey实现接口类型代理
- DotNetty实现TCP通讯
- 对象二进制序列化
RPC调用
服务端
var server = new ServerCreater().CreatetRPC();
server.CheckSign();
server.SetSessionManage(new SessionManage());
server.Register<ITestService, TestService>();
server.Start();
CreateRPC是一个扩展方法,引用CRL.RPC获取
SetSessionManage,自定义Session存储,默认是内存里
CheckSign 处理请求时,进行参数签名验证
客户端接口调用
var clientConnect = new RPCClientConnect("127.0.0.1", 805);
clientConnect.UseSign();
var service = clientConnect.GetClient<ITestService>();
label1:
service.Login();
Console.WriteLine("loginOk");
int? a = 1;
string error;
service.Test1(1, a, out error);
Console.WriteLine("error:" + error);
var obj2 = service.Test2(new TestObj() { Name = "test" });
Console.WriteLine("obj2:" + obj2.ToJson());
Console.ReadLine();
goto label1;
客户端先调用login方法进行登录,并记录服务端返回的token
Test1方法将token回传给服务器以验证登录状态,并进行远程调用
当调用了UseSign方法,就会对提交的参数进行签名,签名KEY为登录后服务端返回的TOKEN,服务端同样按此对签名进行比较
动态webApi
同样基于上文结构,接口定义就不粘贴了
服务端定义
var server = new ServerCreater().CreatetApi();
server.CheckSign();
server.SetSessionManage(new SessionManage());
server.Register<ITestService, TestService>();
var listener = new ServerListener();
//listener.Start("http://localhost:809/");//自定义监听
如果宿主是.NET网站 在web.config增加处理module
<system.webServer>
<modules>
<add name="DynamicModule" type="CRL.DynamicWebApi.DynamicModule" />
</modules>
</system.webServer>
如果是单独程序,启动ServerListener即可
客户端调用
var clientConnect = new CRL.DynamicWebApi.ApiClientConnect("http://localhost:53065");
//var clientConnect = new CRL.DynamicWebApi.ApiClientConnect("http://localhost:8022");
clientConnect.UseSign();
var service = clientConnect.GetClient<ITestService>();
label1:
service.Login();
Console.WriteLine("loginOk");
int? a = ;
string error;
service.Test1(, a, out error);
Console.WriteLine("error:" + error);
var obj2 = service.Test2(new TestObj() { Name = "test" });
Console.WriteLine("obj2:" + obj2.ToJson());
Console.ReadLine();
goto label1;
WebSocket
WebSocket是一个比较特殊的方式,常用来做双工通讯的方式,客户端能往服务端发送数,服务端也能往客户端发送据
除去服务端往客户端发数据,也可以采用接口调用的形式实现,在这里,服务端往客户端发送数据,客户端采用了订阅的方式
服务端实现
var server = new ServerCreater().CreatetWebSocket(8015);
server.CheckSign();
server.SetSessionManage(new SessionManage());
server.Register<ITestService, TestService>();
server.Start();
new CRL.Core.ThreadWork().Start("send", () =>
{
var socket = server.GetServer() as CRL.WebSocket.WebSocketServer;
socket.SendMessage("hubro", new socketMsg() { name = DateTime.Now.ToString() }, out string error);
Console.WriteLine("send msg");
return true;
}, 10);
上面演示代码,服务端开启了一个线程,定时往客户端"hubro"发送数据 socket.SendMessage
客户端实现
var clientConnect = new CRL.WebSocket.WebSocketClientConnect("127.0.0.1", );
clientConnect.UseSign();
clientConnect.SubscribeMessage<socketMsg>((obj) =>
{
Console.WriteLine("OnMessage:" + obj.ToJson());
});
clientConnect.StartPing();
var service = clientConnect.GetClient<ITestService>();
label1:
service.Login();
Console.WriteLine("loginOk");
int? a = ;
string error;
service.Test1(, a, out error);
Console.WriteLine("error:" + error);
var obj2 = service.Test2(new TestObj() { Name = "test" });
Console.WriteLine("obj2:" + obj2.ToJson());
Console.ReadLine();
goto label1;
clientConnect.SubscribeMessage就是订阅消息了,通过订阅的方式,处理服务端发送的数据
可以看到以上各种形式,服务端实现和客户端调用基本相同,定义的接口能重复使用,做接口通讯效果杠杠的
具体实现方式和细节功能参见源码和demo,已经开源,请自行下载
源码地址:
CRL:
https://github.com/hubro-xx/CRL5
RCP:
https://github.com/hubro-xx/CRL5/tree/master/RPC
WebAPI:
https://github.com/hubro-xx/CRL5/tree/master/DynamicWebApi
WebSocket:
https://github.com/hubro-xx/CRL5/tree/master/WebSocket
基于动态代理的WebAPI/RPC/webSocket框架,一套接口定义,多个通讯方式的更多相关文章
- .NET 下基于动态代理的 AOP 框架实现揭秘
.NET 下基于动态代理的 AOP 框架实现揭秘 Intro 之前基于 Roslyn 实现了一个简单的条件解析引擎,想了解的可以看这篇文章 https://www.cnblogs.com/weihan ...
- 实现一个简单的基于动态代理的 AOP
实现一个简单的基于动态代理的 AOP Intro 上次看基于动态代理的 AOP 框架实现,立了一个 Flag, 自己写一个简单的 AOP 实现示例,今天过来填坑了 目前的实现是基于 Emit 来做的, ...
- 动态代理到基于动态代理的AOP
动态代理,是java支持的一种程序设计方法. 动态代理实现中有两个重要的接口和类,分别是InvocationHandler(interface),Proxy(class). 要实现动态代理,必须要定义 ...
- mybatis源码学习:基于动态代理实现查询全过程
前文传送门: mybatis源码学习:从SqlSessionFactory到代理对象的生成 mybatis源码学习:一级缓存和二级缓存分析 下面这条语句,将会调用代理对象的方法,并执行查询过程,我们一 ...
- MyBatis学习(三)MyBatis基于动态代理方式的增删改查
1.前言 上一期讲到MyBatis-Statement版本的增删改查.可以发现.这种代码写下来冗余的地方特别多.写一套没啥.如果涉及到多表多查询的时候就容易出现问题.故.官方推荐了一种方法.即MyBa ...
- Java通过Socket和动态代理实现简易RPC框架
本文转自Dubbo作者梁飞大神的CSDN(https://javatar.iteye.com/blog/1123915),代码简洁,五脏俱全. 1.首先实现RpcFramework,实现服务的暴露与引 ...
- JDK动态代理在RPC框架中的应用
RPC框架中一般都有3个角色:服务提供者.服务消费者和注册中心.服务提供者将服务注册到注册中心,服务消费者从注册中心拉取服务的地址,并根据服务地址向服务提供者发起RPC调用.动态代理在这个RPC调用的 ...
- 带你手写基于 Spring 的可插拔式 RPC 框架(一)介绍
概述 首先这篇文章是要带大家来实现一个框架,听到框架大家可能会觉得非常高大上,其实这和我们平时写业务员代码没什么区别,但是框架是要给别人使用的,所以我们要换位思考,怎么才能让别人用着舒服,怎么样才能让 ...
- Java动态代理——框架中的应用场景和基本原理
前言 之前已经用了5篇文章完整解释了java动态代理的原理,本文将会为这个系列补上最后一块拼图,展示java动态代理的使用方式和应用场景 主要分为以下4个部分 1.为什么要使用java动态代理 2.如 ...
随机推荐
- lightoj 1283 - Shelving Books(记忆化搜索+区间dp)
题目链接:http://www.lightoj.com/volume_showproblem.php?problem=1283 题解:这题很显然一看就像是区间dp,但是单纯的区间dp好像解决不了问题可 ...
- hdu 5969 最大的位或(贪心)
Problem Description B君和G君聊天的时候想到了如下的问题.给定自然数l和r ,选取2个整数x,y满足l <= x <= y <= r ,使得x|y最大.其中|表示 ...
- java中最容易犯错的特殊字符
问题背景 能准确说出下面的java 执行完毕后会打印出什么? System.out.println( String.class.getName()+ ".class"); Syst ...
- Java开学测试
这次开学测试要求做一个信息系统,该系统完成学生成绩录入,修改,计算学分积点和查询学生成绩的简单功能. 下面是我写的代码 //信1805-3班 20183641 赵树琪 package test; im ...
- Sublime运行C++程序教程
前言 传说sublime是全球最好的编辑器,可是只是编辑器啊!!!如果要运行,对于我们这些蒟蒻来说,不得不去使用DEV_C++.我们总是幻想能让sublime变成一个轻量级IDE,那该多好啊!!! 那 ...
- springCloud相关学习资料
SpringCloud相关学习资料 SpringCloud资料参考: 1. 史上最简单的 SpringCloud 教程 | 终章 2. Spring Cloud基础教程 SpringCloud相关: ...
- 史上最详 Thymeleaf 使用教程
前言 操作前建议先参考我的另一篇博客:玩转 SpringBoot 2 快速整合 | Thymeleaf 篇 查看如何在SpringBoot 中使用 Thymeleaf.还有一点需要注意的是:模版页面中 ...
- springmvc 事务控制与数据库隔离级别
springmvc 事物传播与数据库隔离控制 http://www.cnblogs.com/yangy608/archive/2011/06/29/2093478.html 一.Propagation ...
- mybatis #号与$号的区别
区别: 在sql中当传入的参数是字符型,则用#号会带上单引号,不会引起sql注入: 在sql中当传入的参数是字符型,则用$号不会带上单引号,会引起sql注入: 使用范围: 当传入的参数用于查询条件,尽 ...
- 亮剑.NET第二章
第二章主要讲解C#中各种让人模糊不清的概念,用法,类型等等. 1.Equals()与==区别 当比较两个值类型时,二者基本一致,当比较引用类型时,==比较的是引用类型的地址是否一致,即两个引用是否指向 ...