一:什么是RPC

远程过程调用(Remote Procedure Call)。就是调用其他业务方的方法的时候,就像是调用自己本地的方法一样。

二:java rpc实现简介

服务端(使用反射)

(1)服务端写一个接口和一个接口的实现。

(2)服务端维护一个map,key为接口的类名,value为接口的实现类。

(3)服务端通过 ServerSocket 接收客户端发送过来的数据(接口的类名,方法名,请求参数)

(4)服务端根据接口的类名和方法名得到对应实现类的方法,通过反射调用服务

(5)把处理之后的结果通过 ServerSocket  返回给客户端

客户端(动态代理)

(1)把服务端的接口copy过来

(2)写一个代理类,调用服务端方法的时候,通过代理类的 invoke 方法把服务需要的 接口类名,方法名,请求参数 通过 Socket 发送给服务端;接收服务端处理的结果

三:具体实现的代码

(1)服务端的接口声明

public interface IHello {
String sayHello(String string);
}

(2)服务端接口的实现(真正干活的类)

public class HelloServiceImpl implements IHello{

	@Override
public String sayHello(String string) {
// TODO Auto-generated method stub
return "你好:" + string;
}
}

(3)服务端的服务类

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Method;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap; public class RpcServer { private static final HashMap<String, Class<?>> serviceRegistry = new HashMap<>();
private int port; public RpcServer(int port) {
this.port =port;
} public RpcServer register(Class serviceInterface, Class impl) {
serviceRegistry.put(serviceInterface.getName(), impl);
return this;
} public void run() throws IOException { ServerSocket server = new ServerSocket();
server.bind(new InetSocketAddress (port));
System.out.println("start server");
ObjectInputStream input =null;
ObjectOutputStream output =null;
Socket socket=null;
try {
while(true){
socket = server.accept ();
input =new ObjectInputStream(socket.getInputStream());
String serviceName = input.readUTF();
String methodName = input.readUTF();
System.out.println ("客户端调用了 " + methodName + "方法");
Class<?>[] parameterTypes = (Class<?>[]) input.readObject();
Object[] arguments = (Object[]) input.readObject();
Class serviceClass = serviceRegistry.get(serviceName);
if (serviceClass == null) {
throw new ClassNotFoundException(serviceName + " not found");
}
Method method = serviceClass.getMethod(methodName, parameterTypes);
Object result = method.invoke(serviceClass.newInstance(), arguments);
output = new ObjectOutputStream (socket.getOutputStream());
output.writeObject(result);
}
} catch (Exception e){
e.printStackTrace();
}
} public static void main(String[] args) throws IOException {
new RpcServer (8888).register(IHello.class,HelloServiceImpl.class).run();
} }

(4)客户端的实现

import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.net.InetSocketAddress;
import java.net.Socket; import com.cs.rpc.nativ.server.IHello; public class RpcClientProxy<T> implements InvocationHandler { private Class<T> serviceInterface;//被调用者的接口声明
private InetSocketAddress addr;//被调用者的地址(ip+port) public RpcClientProxy(Class<T> serviceInterface, String ip,String port) {
this.serviceInterface = serviceInterface;
this.addr = new InetSocketAddress(ip, Integer.parseInt ( port ));
} public T getClientIntance(){
return (T) Proxy.newProxyInstance (serviceInterface.getClassLoader(),new Class<?>[]{serviceInterface},this);
} @Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Socket socket = null;
ObjectOutputStream output = null;
ObjectInputStream input = null; try {
// 2.创建Socket客户端,根据指定地址连接远程服务提供者
socket = new Socket();
socket.connect(addr); // 3.将远程服务调用所需的接口类、方法名、参数列表等编码后发送给服务提供者
output = new ObjectOutputStream(socket.getOutputStream());
output.writeUTF(serviceInterface.getName());
output.writeUTF(method.getName());
output.writeObject(method.getParameterTypes());
output.writeObject(args); // 4.同步阻塞等待服务器返回应答,获取应答后返回
input = new ObjectInputStream(socket.getInputStream());
return input.readObject();
} finally {
if (socket != null) socket.close();
if (output != null) output.close();
if (input != null) input.close();
}
} public static void main(String[] args) {
RpcClientProxy client = new RpcClientProxy<>(IHello.class,"localhost","8888");
IHello hello = (IHello) client.getClientIntance ();
System.out.println (hello.sayHello ( "socket rpc" ));
}
}

  

RPC-基于原生java实现的更多相关文章

  1. github上的golang双向rpc,基于原生“net/rpc”库实现,可以注册回调

    github上的golang双向rpc,基于原生“net/rpc”库实现,可以注册回调.仅支持一个server和一个client交互. 地址:https://github.com/rocket049/ ...

  2. 分布式架构的基石.简单的 RPC 框架实现(JAVA)

    前言 RPC 的全称是 Remote Procedure Call,它是一种进程间通信方式.允许像调用本地服务一样调用远程服务. 学习来源:<分布式系统架构:原理与实践> - 李林锋 1. ...

  3. 原生java调用webservice的方法,不用生成客户端代码

    原生java调用webservice的方法,不用生成客户端代码 2015年10月29日 16:46:59 阅读数:1455 <span style="font-family: Aria ...

  4. 用jQuery基于原生js封装的轮播

    我发现轮播在很多网站里面都用到过,一个绚丽的轮播可以为网页增色不少,最近闲来无事,也用原生js封装了一个轮播,可能不像网上的插件那么炫,但是也有用心去做.主要用了闭包的思想.需要传递的参数有:图片地址 ...

  5. 基于纯Java代码的Spring容器和Web容器零配置的思考和实现(3) - 使用配置

    经过<基于纯Java代码的Spring容器和Web容器零配置的思考和实现(1) - 数据源与事务管理>和<基于纯Java代码的Spring容器和Web容器零配置的思考和实现(2) - ...

  6. 基于原生js的图片延迟加载

    当页面图片比较多的时候,我们通常会做一个延迟加载,避免页面打开时一下子的请求数太多,加载过慢影响用户体验. 如果项目用了jquery框架,则可以直接用 jquery.lazyload.可在jquery ...

  7. 基于原生js的返回顶部组件,兼容主流浏览器

    基于原生js的返回顶部插件,兼容IE8及以上.FF.chrome等主流浏览器. js文件中封装了getScrollTop()和changeScrollTop()函数分别用于获取滚动条滚动的高度和修改滚 ...

  8. 原生Java代码拷贝目录

    拷贝.移动文件(夹),有三方包commons-io可以用,但是有时候有自己的需求,只能使用原生java代码,这时可以用以下几种方式进行拷贝: 1.使用系统命令(Linux)调用 此种方式对操作系统有要 ...

  9. 一个基于原生JavaScript开发的、轻量的验证码生成插件

    Vcode.js 一个基于原生JavaScript开发的.轻量的验证码生成插件 V: 1.0.0 DEMO:https://jofunliang.github.io/Vcode.js/example. ...

  10. RPC基于http协议通过netty支持文件上传下载

    本人在中间件研发组(主要开发RPC),近期遇到一个需求:RPC基于http协议通过netty支持文件上传下载 经过一系列的资料查找学习,终于实现了该功能 通过netty实现文件上传下载,主要在编解码时 ...

随机推荐

  1. vue开发知识点总结

    一.vue介绍 Vue.js 是一套构建用户界面(UI)的渐进式JavaScript框架,是一个轻量级MVVM(model-view-viewModel)框架. 二.数据绑定 最常用的方式:Musta ...

  2. Apache+Mysql+PHP 套件

    Apache+Mysql+PHP 套件   最近要装个Apache+Mysql+PHP的一个环境. google下后,发现现在的安装变得越来越简单了.不再需要麻烦的配置安装,只需简单执行个sh就搞定了 ...

  3. classloader加载class的流程及自定义ClassLoader

    java应用环境中不同的class分别由不同的ClassLoader负责加载.一个jvm中默认的classloader有Bootstrap ClassLoader.Extension ClassLoa ...

  4. 【Luogu4221】[WC2018] 州区划分

    题目链接 题目描述 略 Sol 一个州合法就是州内点形成的子图中 不存在欧拉回路(一个点也算欧拉回路). 这个东西显然就状压 dp 一下: 设 \(f[S]\) 表示当前考虑了 \(S\) 这个集合内 ...

  5. SpringCloud学习系列-构建部门微服务提供者Module

    1.新建microservicecloud-provider-dept-8001 2.POM <project xmlns="http://maven.apache.org/POM/4 ...

  6. Java——容器(Collection)

    Collection是一个接口,定义了一系列的方法.   [常见方法]  

  7. C++STL手写版

    手写STL,卡常专用. node为变量类型,可以自由定义,以下不再赘述. 1.stack(栈) 开一个数组,和一个top指针,压栈时++,弹栈时--即可. struct stack{ int tp;n ...

  8. Leetcode 7. Reverse Integer(水)

    7. Reverse Integer Easy Given a 32-bit signed integer, reverse digits of an integer. Example 1: Inpu ...

  9. Java基础之方法详解

    方法的所属性 在Java的语言中,方法相当于C语言中的函数,但是它与传统的函数也有着明确的不同:在结构化的语言中,函数是一等公民,整个程序是由一个个函数组成的:但是在面向对象的语言里,类是一等公民,整 ...

  10. scipy几乎实现numpy的所有函数

    NumPy和SciPy的关系?   numpy提供了数组对象,面向的任何使用者.scipy在numpy的基础上,面向科学家和工程师,提供了更为精准和广泛的函数.scipy几乎实现numpy的所有函数, ...