- client通过调用stub来屏蔽网络通信的细节,这样就不用再client中写网络发送和接收的代码实现
package com.bill.rpc02;
import com.bill.rpc.common.User;
import java.io.IOException;
/**
* @Auther: wangchunwen
* @Date: 2023/1/2 - 01 - 02 - 22:42
* @Description: com.bill.rpc02
* @version: 1.0
*/
public class Client {
public static void main(String[] args) throws IOException {
Stub stub = new Stub();
System.out.println(stub.findUser(123).toString());
}
}
- Stub进行网络代理,只能代理一个方法findUser,如果这个接口增加一个方法,则需要重新修改Stub,需要进一步进行优化。
package com.bill.rpc03;
import com.bill.rpc.common.IUserService;
/**
* @Auther: wangchunwen
* @Date: 2023/1/3 - 01 - 03 - 22:43
* @Description: com.bill.rpc03
* @version: 1.0
*/
public class Client {
public static void main(String[] args) {
IUserService service = Stub.getStub();
System.out.println(service.findUser(123));
}
}
- client:实现一个代理,这个代理可以提供一个类。这个类实现了IUserService接口,自然而然就实现了这个接口的所有方法,这样通过创建的这个类,就可以调用这个类里面的方法,同时实现这个方法的时候也帮忙屏蔽了网络通信层面的东西,实现原理:当我调用findUser方法的时候,这个代理帮我添加了一些网络服务的代码,帮我实现网络通信功能。本质上这个是通过设计模式中动态代理模式实现的。
- 如何通过代理创建这个类?
- 如果通过自己实现一个类来实现类的创建,那么如果新增接口后则需要再写一个类,比较麻烦;
- 考虑是否可以通过动态生成一个类,动态产生一个新的类;
- 动态代理是rpc的核心之一;
- Stub实现
package com.bill.rpc03;
import com.bill.rpc.common.IUserService;
import com.bill.rpc.common.User;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.net.Socket;
/**
* @Auther: wangchunwen
* @Date: 2023/1/3 - 01 - 03 - 22:44
* @Description: com.bill.rpc03
* @version: 1.0
*/
public class Stub {
public static IUserService getStub(){
InvocationHandler h = new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 写出去
Socket s = new Socket("127.0.0.1",8888);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(baos);
dos.writeInt(123);
s.getOutputStream().write(baos.toByteArray());
s.getOutputStream().flush();
// 读进来
DataInputStream dis = new DataInputStream(s.getInputStream());
int id = dis.readInt();
String name = dis.readUTF();
User user = new User(id,name);
System.out.println(user);
dos.close();
s.close();
return user;
}
};
Object o = Proxy.newProxyInstance(IUserService.class.getClassLoader(),new Class[] {IUserService.class},h);
System.out.println(o.getClass().getName());
System.out.println(o.getClass().getInterfaces()[0]);
return (IUserService)o;
}
}
- Stub说明
- InvocationHandler是一个处理器,用来处理调用;
- 当调用findUser方法是,实际上是调用处理器中invoke方法,invoke方法中三个参数
- 参数1:谁在调用这个方法?
- 参数2:调用的是哪个方法?
- 参数3:调用的传入的参数是什么?
- 通过动态代理创建这个类,创建动态代理通过Proxy.newProxyInstance创建,三个参数
- 参数1:要实现接口的classloader,表明要创建哪个接口的实现类
- 参数2:要实现接口的class,表明要创建哪个接口的实现类
- 参数3:使用的是哪个处理器,这个处理器可以将哪些代码塞进来