目标
写个简单的rpc 调用
Rpc大致思路
定义一个接口HelloService 放在iface.jar中
应用P中引用iface.jar 实现接口HelloService进行处理任务 注册bean到spring中
应用C中, 通过spring获取HelloService的实例phService
调用phService.echo(xxx)方法,获得返回结果
应用P运行在1个jvm中 应用C运行在另1个jvm中
phService实质为一个代理对象
该代理对象通过把调用的参数封装,序列化后,通过网络传输给应用P
应用P根据收到参数后,调用处理接口相应的实现类,并将结果回传给应用C端
最终代理对象返回收到的运行结果
序列化-知识点补充
进行RPC调用必然要涉及对方法参数的序列化。
序列化框架有很多, 如protobuf、thrift、hession等
dubbo的rpc是支持多种序列化方式,如Java原生、Kryo、webservice等
spring cloud的http调用也算一种序列化方式
有了序列化工具,不仅仅是跨JVM的方法调用,还能跨语言调用。
本次示例使用java原生序列化
初版代码
所用到包
1
2
3
4
5
6
7
|
import java.io.*;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.concurrent.*;
import java.util.concurrent.locks.LockSupport;
import com.google.common.reflect.Reflection;
|
定义服务接口与服务实现类
1
2
3
4
5
6
7
8
9
10
11
|
interface HelloService{
public String echo(String msg);
}
class HelloServiceImpl implements HelloService{
@Override
public String echo(String msg) {
String result = "【" + msg + "】 is deal";
return result;
}
}
|
序列化工具类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
|
class Util {
public static byte[] obj2byte(Object obj) {
byte[] bytes = null;
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = null;
try {
oos = new ObjectOutputStream(bos);
oos.writeObject(obj);
oos.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
oos.close();
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
bytes = bos.toByteArray();
return bytes;
}
public static Object byte2Obj(byte[] bytes) {
Object obj = null;
ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
ObjectInputStream ois = null;
try {
ois = new ObjectInputStream(bis);
obj = ois.readObject();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally {
try {
ois.close();
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return obj;
}
}
|
使用反射调用服务实现类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
|
class DemoRpc{
static HelloService tagert = new HelloServiceImpl();
static HashMap ifaceMap = new HashMap();
public static void main(String[] args) throws Exception {
// 最初版-生产者端-直接调用
HelloService provider0 = tagert;
String result = provider0.echo("v0-版本");
System.out.println(result);
// v1版-生产者端-反射调用
HelloService provider1 = tagert;
String methondName = "echo";
String[] params = new String[1];
params[0] = "v1-版本";
Method method = HelloService.class.getMethod(methondName, String.class);
result = (String) method.invoke(provider1, params);
System.out.println(result);
// v2版本-客户端传参-生产者端接收参数-反射调用
ifaceMap.put("helloService",HelloServiceImpl.class.getTypeName());
RpcPojo clientSide = new RpcPojo();
clientSide.ifaceName = "helloService";
clientSide.methondName = "echo";
clientSide.params = new String[1];
clientSide.params[0]= "v2-版本";
clientSide.paramsTypes = new Class[1];
clientSide.paramsTypes[0]= clientSide.params[0].getClass();
byte[] netDatas = Util.obj2byte(clientSide);
RpcPojo providerSide = (RpcPojo) Util.byte2Obj(netDatas);
method = HelloService.class.getMethod(providerSide.methondName, providerSide.paramsTypes);
Object provider2 = Class.forName((String) ifaceMap.get("helloService")).newInstance();
result = (String) method.invoke(provider2, providerSide.params);
System.out.println(result);
}
}
class RpcPojo implements Serializable {
private static final long serialVersionUID = -1055524749130316395L;
String ifaceName;
String methondName;
Object[] params;
Class[] paramsTypes;
Object result;
}
|
初版 -> v1版 -> v2版
这里以过渡的形式说明了rpc的大致流程,但目前还没看到动态代理的踪迹。
下个版本会通过加入动态代理的使用,说明服务是怎么注册的。
文章作者
duansheli
上次更新
2019-12-25
(325c7b3)