RPC演进+动态代理补充
RPC演进
-
RPC Remote Procedure call,远程方法调用,重点在方法调用(不支持对象的概念)
-
单机到分布式 -> 分布式通信 -> 最基本:二进制数据传输TCP/IP
-
场景:server端连数据库。client把id传给server,server中调用UserService(继承IUserService接口)中的findUserById(),然后从server中获得user对象。
01
- Java基础里的socket编程
- 制定监听端口,用inputstream,outputstream写进去读出来
02
- 封装网络传输部分
- 建个Stub(客户端)类,作为代理
- 把client端原来的getbyid方法放到Stub里(相当于把跟网络相关部分拎出来封装成一个类),这样client中就只用new Stub类,然后调用stub里的方法
03
- Stub提供一个IUserService,可以在client得到一个UserService对象,然后远程访问findUserById()
- 基于动态代理,invoke里放联网,写,读,最后返回读到的user
- 缺点:这一版里还是硬往服务器端传的id,相当于只适配findUserById()
04
- 基于03,在invoke里将方法名(.getName),参数类型(.getParameterTypes)(因为有可能重写)和参数(args)传给server,然后在server那边再通过方法名和参数类型找到调用的方法
- 服务器端改进:读入方法名,参数类型,参数;通过反射 service.getClass.getMethod(methodName, parameterTypes)找到该方法method,然后用method.invoke(service, args)调用
- 解决了对同一接口中不同方法的支持,可以随意增添新的方法;
- 缺点:返回值还没处理;传回来的user还是id name拆解的,如果user定义变了,这个代码还是得变
05
- server端writeObject(user),直接写入一个对象
- (即返回值用object封装,支持任意对象返回值)
06
- 把getStub的返回值改成Object(原来是User),getStub加一个Class类型的参数clazz
- 在client的main中调用的时候,把需要的类.Class传到getStub里
- 在getStub的invoke中,把clazz也一起传给server
- 在server中,先找类,再在类中找方法
07
- (他这里好像就是换了个对象测了一下06)
08
- 使用序列化框架Hessian
课程:马士兵教育专属 马士兵老师讲:RPC的演化过程,36行代码透彻解析RPC,听不懂你打我!_哔哩哔哩_bilibili
补充:动态代理
- 分析:test中,proxy.sing调用sing方法,会调动invoke,此时method为sing,然后return method.invoke(),调bigstar.sing,把bigstar.sing的返回值返回给method.invoke(),再返到test中的String sing这里。
- Test类
public class Test {
public static void main(String[] args) {
BigStar star = new BigStar("xiaoyang");
Star proxy = ProxyUtil.createProxy(star);
String sing = proxy.sing("17 years");
System.out.println(sing);
proxy.dance();
}
}
- Star接口类
public interface Star {
String sing(String name);
void dance();
}
- BigStar类
public class BigStar implements Star{
private String name;
public BigStar(String name){
this.name = name;
}
public String sing(String name){
System.out.println(this.name+"正在唱:"+name);
return "thank you";
}
public void dance(){
System.out.println(this.name+"正在跳舞");
}
}
- ProxyUtil类
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ProxyUtil {
public static Star createProxy(BigStar bigStar){
/*
* (ClassLoader loader,指定类加载器(直接用当前类)
* Class<?>[] interfaces,指定生成的代理有哪些方法,接口数组
* InvocationHandler h) 指定生成的代理对象要干什么事情
*
* */
Star o = (Star)Proxy.newProxyInstance(ProxyUtil.class.getClassLoader(),
new Class[]{Star.class}, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if(method.getName().equals("sing")){
System.out.println("准备话筒");
}
else if(method.getName().equals("dance")){
System.out.println("准备场地");
}
return method.invoke(bigStar,args);
}
});
return o;
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通