远程方法调用(RPC)的结构如图所示,一般我们还会有一个注册中心如zk、dubbo、eureka等,服务提供方将自己的向外提供的接口注册在上面并暴露IP、端口等信息,而消费方通过在注册中心注册获取可以使用的接口列表及其他相关信息,从而调用服务方提供的各种方法。
简单来说,服务提供者将对外接口注册,并监听调用该接口的socket请求;当请求到来时,创建一个子线程,获取请求中传递的消费者期望调用方法、参数等信息,执行后将结果通过socket返回。
而消费者,获得服务提供方所暴露接口,创建其代理对象(即动态代理),通过服务提供方暴露的Ip和Port建立socket链接,传递请求方法和参数,并接受返回值。
下面说一下动态代理,这里面主要涉及了Proxy代理类和InvocationHandler接口,前者用于获取代理对象;通过后者可以利用代理对象调用原对象的方法,并进行额外处理,在RPC中代理主要作用于服务消费方。
消费者通过服务方暴露的接口生成代理对象,在InvocationHandler中重写invoke方法,在其中与服务提供方建立socket连接,发生请求方法和参数并获取返回值。具体逻辑可以这样写
注意,本部分代码未经验证,只是写出了大体的逻辑,异常也未捕获
//客户端代码
//获取代理对象
public class RpcProxyFactory {
public static <T>T getProxy(T interFace) {
return (T)Proxy.newProxyInstance(interFace.getClass().getClassLoader(), interFace,
new myHandler());
}
}
//重写了invoke方法,就是代理对象的方法执行的时候真正与服务提供方建立连接并获得返回结果的地方。
public class myHandler extends InvocationHandler{
String ip="127.0.0.1";
String port = "111";
@override
public object invock(Method method, object[] args, Proxy proxy) {
Socket socket = new socket(ip,port);
ObjectOutPutStream out= new ObjectOutputStream(socket.getOutputStream());
out.writeUTF(method.getName());//请求方法名
out.writeObject(method.getParameterTypes());//参数类型
output.writeObject(args);//参数值
ObjectInputStream input = new ObjectInputStream(socket.getInputStream());
Object result = input.readObject();//获取返回值
return result;
//socket 、input、output记得要close
}
}
//服务端代码
接受客户端代理对象socket连接,每到来一个请求建立一个线程,处理请求方法,返回处理结果。
public class ServiceServer{
String port = "111";
/*
* service 为向外暴露的服务接口
*/
public static void provide(Obejct service) {
SockerServer server = new SockerServer(port);
while(true) {
socket.accept();
new Thread(new Runable() {
@override
public void run() {
ObejctInputStream input = new ObejctInputStream(server.getInputStream());
String methodName = input.readUTF();
Class<?>[] parameterTypes = (Class<?>[]) input.readObject();
Object[] arguments = (Object[]) input.readObject();
ObjectOutputStream output = new ObejctInputStream(server.getOutputStream());
Method method = service.getClass().getMethod(methodName, parameterTypes);
Object result = method.invoke(service, arguments);
output.writeObject(result);
//socketserver 、input、output记得要close
}
}).start();
}
}
}
//服务示例
public interface HelloService {
public String sayHello(String name);
}
服务实现
public class HelloServiceImpl implements HelloService{
@Override
public String sayHello(String name) {
return "hello "+name;
}
}
//服务端启动
public class RpcProvider {
public static void main(String[] args) throws Exception {
HelloService service = new HelloServiceImpl();
ServiceServer.provide(service);
}
}
//客户端调用
public class RpcConsumer {
public static void main(String[] args) throws Exception {
HelloService proxy = RpcProxyFactory.getProxy(HelloService.class);
String result = proxy.sayHello("world");
System.out.println(result);
}
}
这里有一篇文章写的很详细RPC原理简析——三分钟看完 - 简书