小迷妹:哥,我问你一个问题啊?
我:啥问题啊?
小迷妹:你最近嘴里面天天念叨的rpc 是啥啊?
我:好,哥今天给你普及一下,什么是rpc。
小迷妹:哇啊,哥哥你好棒啊。
我:哈哈,还好还好,你不要这么崇拜我。
RPC,就是Remote Procedure Call 远程过程调用
小迷妹:啥叫远程过程调用啊,咋搞的那么高深?
我:我给你举个例子,就是说当你不想下楼吃饭的时候,然后拿起电话,叫了一个外卖,然后外卖小哥就把外卖送过来了,这个就是远程过程调用。
小迷妹:哥,好像到中午了,刚好我不想下楼,那你帮我远程调用一下把。
我:。。。。。
现如今随着互联网的发展,更多的企业采用了分布式服务,解决了服务单点问题和服务功能一致性问题 ,以应对流量快速的增长。那么分布式服务之间 就会存在调用的问题。
举个例子
用户模块 是一个服务,交易模块 是一个服务。如果用户服务调用交易服务,因为它是分布到两个服务器上的是跨进程的,所以不能像调用本地方法那样,需要我们做一些处理,这就引入了rpc
来我们画张图
1.首先启动交易模块服务,会向外暴漏ip地址和port 端口号。
2.用户模块,通过动态代理,获取到接口和参数。
3.把获取到的接口和参数,以序列化的方式,调用交易模块暴漏出来的ip地址和port 底层通过网络协议,把序列化的数据,传输到交易模块。
4.交易模块,会把客户端传输过来的序列化数据,进行反序列化。
5.反序列化得到的接口和参数,在根据接口名称和参数,反射得到相应的实现类,然后调用实现类最后得到result。
6.最后把result放到数据流中,在根据刚刚建立的长连接,通过网络协议把result返回到客户端。
总结一下,rpc 主要解决以下两点:
/**
* Created by guyan on 2019/9/7 17:21
*/
public class RemoteInvokeHandler implements InvocationHandler {
private String ip;
private int port;
public RemoteInvokeHandler(String ip, int port) {
this.ip = ip;
this.port = port;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("进入代理类");
ReqParam param=new ReqParam();
param.setClassName(method.getDeclaringClass().getName());
param.setMethodName(method.getName());
param.setParameters(args);
System.out.println("param.toString() = " + param.toString());
return new RpcNetSend(ip,port).send(param);
}
}
/**
* Created by guyan on 2019/9/7 17:23
*/
public class RpcNetSend {
private String ip;
private int port;
public RpcNetSend(String ip, int port) {
this.ip = ip;
this.port = port;
}
public Object send(ReqParam param) {
Socket socket = null;
ObjectOutputStream objectOutputStream = null;
ObjectInputStream objectInputStream = null;
Object result = null;
try {
socket = new Socket(ip, port);
objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
objectOutputStream.writeObject(param);
objectOutputStream.flush();
objectInputStream = new ObjectInputStream(socket.getInputStream());
result = objectInputStream.readObject();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally {
try {
if (objectInputStream != null) {
objectInputStream.close();
}
if (objectOutputStream != null) {
objectOutputStream.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return result;
}
}
/**
* Created by guyan on 2019/9/7 17:14
*/
public class RpcProxyClient {
public T clientProxy(final Class interfaceClass, String ip, int port) {
return (T) Proxy.newProxyInstance(interfaceClass.getClassLoader(), new Class>[] { interfaceClass },
new RemoteInvokeHandler(ip, port));
}
}
**
* Hello world!
*
*/
public class App
{
public static void main( String[] args )
{
IMsgService iMsgService=new RpcProxyClient().clientProxy(IMsgService.class,"localhost",8080);
String result = iMsgService.sayMsg("i am guyan");
System.out.println("result = " + result);
}
}
/**
* Created by guyan on 2019/9/7 11:15
*/
public interface IMsgService {
String sayMsg(String msg);
String saveUser(UserDto user);
}
/**
* Created by guyan on 2019/9/7 12:24
*/
@RpcService(IMsgService.class)
public class IMsgServiceImpl implements IMsgService {
@Override
public String sayMsg(String msg) {
System.out.println("IMsgService.sayMsg the msg is " + msg);
return "sayMsg="+msg;
}
@Override
public String saveUser(UserDto user) {
System.out.println("IMsgService.saveUser the user is" + user);
return "SUCCESS";
}
}
/**
* Created by guyan on 2019/9/8 15:33
*/
public class RpcProxyServer01 implements InitializingBean, ApplicationContextAware {
private ExecutorService executorService = Executors.newCachedThreadPool();
/**
* 端口号
*/
private int port;
/**
* key:serviceName value:service实例化
*/
private ConcurrentMap map=new ConcurrentHashMap<>();
public RpcProxyServer01(int port) {
this.port = port;
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("spring bean 初始化之后");
ServerSocket socketServer = null;
try {
socketServer = new ServerSocket(port);
while (true) {
Socket accept = socketServer.accept();
executorService.submit(new ProcessorHandler(accept, map));
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (socketServer != null) {
try {
socketServer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
System.out.println("spring 手动注入!");
Map beans = applicationContext.getBeansWithAnnotation(RpcService.class);
if (beans.isEmpty()){
return;
}
for(Object bean:beans.values()){
RpcService rpcService = bean.getClass().getAnnotation(RpcService.class);
String serviceName = rpcService.value().getName();
map.put(serviceName,bean);
}
}
}
/**
* Created by guyan on 2019/9/7 14:03
*/
public class ProcessorHandler implements Runnable {
private Socket socket;
/**
* key:serviceName value:service实例化
*/
private ConcurrentMap map = new ConcurrentHashMap<>();
public ProcessorHandler(Socket socket, ConcurrentMap map) {
this.socket = socket;
this.map = map;
}
@Override
public void run() {
System.out.println("进入处理类");
ObjectInputStream objectInputStream = null;
ObjectOutputStream objectOutputStream = null;
try {
objectInputStream = new ObjectInputStream(socket.getInputStream());
ReqParam reqParam = (ReqParam) objectInputStream.readObject();
Object result = invoke(reqParam, map);
objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
objectOutputStream.writeObject(result);
objectOutputStream.flush();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally {
try {
if (objectInputStream != null) {
objectInputStream.close();
}
if (objectOutputStream != null) {
objectOutputStream.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 通过反射机制找到相应的方法
*
* @param param
* @return
*/
private Object invoke(ReqParam param, ConcurrentMap map) {
System.out.println("param = " + param);
Object service = map.get(param.getClassName());
if (null == service) {
throw new NullPointerException("the service is null,the service name is=[{}]" + param.getClassName());
}
Object[] parameters = param.getParameters(); //获取到参数
Class>[] types = new Class[parameters.length]; //获取到参数类型
for (int i = 0; i < parameters.length; i++) {
types[i] = parameters[i].getClass(); //存到class type 数组中
}
Object result = null;
try {
Class clazz = Class.forName(param.getClassName()); //根据类名反射出class
Method method = clazz.getMethod(param.getMethodName(), types); //class 根据方法名和参数获取相应的方法
result = method.invoke(service, parameters); //通过传进来的实例类,和参数获取结果
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return result;
}
}
**
* Hello world!
*/
public class App {
public static void main(String[] args) {
ApplicationContext applicationContext=new AnnotationConfigApplicationContext(SpringConfig.class);
((AnnotationConfigApplicationContext) applicationContext).start();
System.out.println("spring 初始化成功");
}
}