RPC(Remote Procedure Call Protocool)远程过程调用。
为什么用RCP
各个模块可能部署在不同的主机上(主要的原因是不在一个内存空间,不能直接调用),需要远程通信访问,通过HTTP或者RPC的方式
调用的流程
1、解决通信问题,即建立TCP链接,通过链接进行数据传输
2、解决寻址问题,如何寻找B服务器上被调用的方法,可以理解为对外暴露方法的方式
3、客户端序列化传输到服务器
4、服务器反序列化解析处理结果,序列化返回
5、客户端反序列化解析结果
流行的RPC框架
Dubbo、Thrif(跨语言)、WebService(基于SOAP协议)、Hessian、grpc都是基于RPC原理实现的
客户端和服务端都可以分成4层,最底层是socket接受发送请求,上面一层是序列化和反序列化,再往上是代理层,最顶端是用户调用层
1、通信(TCP协议)
2、序列化和反序列化,回顾之前的如(java原生方法,avro,protobuf,json,xml)
3、IO(BIO/NIO/AIO)
4、反射
5、代理
6、暴露服务:ip/端口/目标类/参数,如WebService对应的wsdl,dubbo对应//url
创建一个两个maven项目rpc-server/rpc-client
server有两个模块api和provider,api对外提供接口,provider发布服务
public class RpcRequest implements Serializable
{
private String className;
private String methodName;
private Object[] parameters;
public String getClassName()
{
return className;
}
public void setClassName(String className)
{
this.className = className;
}
public String getMethodName()
{
return methodName;
}
public void setMethodName(String methodName)
{
this.methodName = methodName;
}
public Object[] getParameters()
{
return parameters;
}
public void setParameters(Object[] parameters)
{
this.parameters = parameters;
}
@Override
public String toString()
{
return "RpcRequest{" + "className='" + className + '\'' + ", methodName='" + methodName + '\'' + ", parameters=" + Arrays.toString(parameters) + '}';
}
}
provider
依赖api
provider的主要功能
开启一个线程池不断的处理客户端的请求
启动服务App App
public static void main(String[] args)
{
HelloService service = new HelloServiceImpl();
RpcProxyServer proxyServer=new RpcProxyServer();
proxyServer.publiser(service,8011);
}
代理服务 RpcProxyServer
1、线程池:
//创建线程池
ExecutorService threadPool = Executors.newFixedThreadPool(5);
2、循环阻塞
serverSocket = new ServerSocket(port);
while(true)
{
Socket socket = serverSocket.accept();
threadPool.execute(new ProcessorHandler(socket,service));
}
3、处理输入输出流的线程 ProcessorHandler
package com.gupao.rpc;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.Socket;
/**
* @Autor : heyanfeng22
* @Description :
* @Date:Create:in 2019/6/28 15:12
* @Modified By:
*/
public class ProcessorHandler implements Runnable
{
private Socket socket;
private Object service;
public ProcessorHandler(Socket Socket,Object service)
{
this.socket = Socket;
this.service = service;
}
@Override
public void run()
{
//处理请求
ObjectInputStream objectInputStream=null;
ObjectOutputStream objectOutputStream=null;
try
{
objectInputStream = new ObjectInputStream(socket.getInputStream());
RpcRequest rpcRequest = (RpcRequest) objectInputStream.readObject();
//反射调用本地服务
Object result=invoke(rpcRequest);
//返回
objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
objectOutputStream.writeObject(result);
objectOutputStream.flush();
}
catch (Exception e)
{
e.printStackTrace();
}
finally
{
if (objectInputStream!=null)
{
try
{
objectInputStream.close();
}
catch (IOException e)
{
e.printStackTrace();
}
}
if(objectOutputStream!=null)
{
try
{
objectOutputStream.close();
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
}
private Object invoke(RpcRequest rpcRequest) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException
{
String className = rpcRequest.getClassName();
String MethdName = rpcRequest.getMethodName();
Object[] parameters = rpcRequest.getParameters();//拿到请求参数
//获得每个参数的类型
Class>[] types = new Class[parameters.length];
for (int i=0;i
public static void main(String[] args)
{
//通过代理类调用服务
RpcProxyClient proxyClient = new RpcProxyClient();
HelloService service = proxyClient.createClient(HelloService.class,"localhost",8011);
String result = service.sayHello("哈哈哈");
System.out.println(result);
}
代理类 RpcProxyClient
public class RpcProxyClient
{
public T createClient(Class inerfaceClazz,String ip,int port)
{
return (T)Proxy.newProxyInstance(inerfaceClazz.getClassLoader(),new Class>[]{inerfaceClazz},new RemoteInvocationHandler(ip,port));
}
}
代理实现类 RemoteInvocationHandler
public class RemoteInvocationHandler implements InvocationHandler
{
private String host;
private int port;
public RemoteInvocationHandler(String host, int port)
{
this.host = host;
this.port = port;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
{
//请求会进入到这里
System.out.println("come in");
//在这里处理请求
//请求数据的包装
RpcRequest rpcRequest=new RpcRequest();
rpcRequest.setClassName(method.getDeclaringClass().getName());
rpcRequest.setMethodName(method.getName());
rpcRequest.setParameters(args);
//远程通信
RpcNetTransport netTransport=new RpcNetTransport(host,port);
Object result=netTransport.send(rpcRequest);
return result;
}
}
具体请求类 RpcNetTransport
public class RpcNetTransport
{
private String host;
private int port;
public RpcNetTransport(String host, int port) {
this.host = host;
this.port = port;
}
public Object send(RpcRequest request){
Socket socket=null;
Object result=null;
ObjectOutputStream outputStream=null;
ObjectInputStream inputStream=null;
try {
socket=new Socket(host,port); //建立连接
outputStream =new ObjectOutputStream(socket.getOutputStream());//网络socket
outputStream.writeObject(request); //序列化()
outputStream.flush();
inputStream=new ObjectInputStream(socket.getInputStream());
result=inputStream.readObject();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}finally {
if(inputStream!=null){
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(outputStream!=null){
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return result;
}
}