从零实现RPC之代理模式应用 | Enplee's blog
0%

从零实现RPC之代理模式应用

RPC的概念本质就是本地调用远程主机的方向像是在本地调用一样简单。对于使用RPC框架的开发人员来说,他们最终只需要写出一行Interface::Method(), 就可以实现远程的方法调用。那么就需要框架来实现如何屏蔽掉调用远程方法时候的一系列操作: 构建RpcRequest消息、消息发送,结果接受并按照方法返回。这个过程刚好可以通过代理模式实现。

代理模式

什么是代理模式呢?就像生活中的代理一样,被代理的类只负责核心的业务逻辑,而代理类负责处理核心逻辑之外的工作。所有对被代理的请求全部被都交给代理类全权打理。这样,一是可以增加额外的功能而不侵入核心逻辑的代码,同时这整个过程对完是完全不可见的。对于外部访问来说,他仅仅是调用了统一个接口的方法。

  • 静态代理

静态代理是最容易实现的代理模式。设计思想是代理类与被代理类实现相同的接口,并且代理类的内部组合了被代理类。代理类的内部实现了接口的方法,但是这个方法一定会调用了被代理类的方法,只不过在被代理类方法执行前后,增加额外的处理逻辑。之后发挥多态的特点,所有请求都是走的代理类。代理类的方法被调起的时候,被代理类或者说委托类的方法也会在内部被调用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public interface BuyHouse {
void buyHosue();
}
// 被代理类
public class BuyHouseImpl implements BuyHouse {
@Override
public void buyHosue() {
System.out.println("我要买房");
}
}

public class Proxy implements BuyHouse {

BuyHouseImpl buyHouseImpl;

@Override
public void buyHosue() {
System.out.println("-----");
buyHouseImpl.buyHosue();
System.out.println("-----");
}
}
  • JDK动态代理

静态代理的实现方式简单,但是如果我们有很多的业务逻辑类需要做代理,就要为每一个类同时创建一个代理类。如果需求有更改,还要做大量的修改。JDK为我们提供了动态代理的方式,我们只需要实现InvokationHanlder,JDK就会在运行的时候动态的创建出一个代理类。

1
Proxy.newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler invocationHandler)

需要传入委托类的类加载器、实现接口以及InvocationHandler。InvocationHandler是需要手动实现invoke方法。

在invoke(),方法参数是委托类被方法被调用时候的各种参数,如方法参数、方法参数类型等。获得的代理对象在调用委托类方法时候,其实是执行的Invoke方法中的逻辑。

JDK动态代理相对于静态代理打打减少了我们开发任务。但是JDK代理只支持为实现了接口的方法提供代理对象,由于java是单继承模式,无法为没有实现接口的类进行代理。这时候就需要另外一种动态代理方式:CGLib.

  • CGLib动态代理

CGLib动态代理采用字节码动态织入的方式。采用继承的方式,通过字节码技术为委托类生成一个子类并用子类去拦截所有父类的方法调用。CGLib的性能比JDK动态代理要高,但是生成代理对象却比较慢。

RPC中的代理模式应用

选型: 优先使用动态代理,而且根据远程调用的特性,一定是基于接口的。所以使用JDK提供的动态代理方式:

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
47
48
49
50
51
52
53
54
55
56
@Slf4j
public class RpcClientProxy implements InvocationHandler {

private static final String INTERFACE_NAME = "interfaceName :";
private final RpcServiceConfig rpcServiceConfig;
private final RpcRequestTransposter rpcRequestTransposter;

public RpcClientProxy(RpcServiceConfig rpcServiceConfig, RpcRequestTransposter rpcRequestTransposter) {
this.rpcServiceConfig = rpcServiceConfig;
this.rpcRequestTransposter = rpcRequestTransposter;
}

@SuppressWarnings("unchecked")
public <T> T getProxy(Class<T> clazz) {
return (T) Proxy.newProxyInstance(clazz.getClassLoader(),new Class<?>[]{clazz}, this);
}

@SuppressWarnings("unchecked")
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//封装RpcReques
log.info("invoke method [{}]", method.getName());
RpcRequest rpcRequest = RpcRequest.builder().methordName(method.getName())
.args(args)
.argsType(method.getParameterTypes())
.requestId(UUID.randomUUID().toString())
.group(rpcServiceConfig.getGroup())
.version(rpcServiceConfig.getVersion())
.serviceName(method.getDeclaringClass().getName()).build();
// rpcTransport::sendRpcRequest
RpcResponce<Object> rpcResponce = null;
CompletableFuture<RpcResponce<Object>> future = (CompletableFuture<RpcResponce<Object>>) rpcRequestTransposter.sendRpcRequest(rpcRequest);
log.info("get future,wait process coming......");
// future::get
rpcResponce = future.get();
// check
this.check(rpcRequest,rpcResponce);
//return
return rpcResponce.getData();
}

public void check(RpcRequest rpcRequest, RpcResponce<Object> rpcResponce) {
// judge null:invoke fail
if(rpcResponce == null) {
throw new RpcException(RpcErrorMessageEnum.SERVICE_INVOKATION_FAILURE,INTERFACE_NAME+rpcRequest.getServiceName());
}
// requestId:request resp not match
if(!rpcRequest.getRequestId().equals(rpcResponce.getRequstId())){
throw new RpcException(RpcErrorMessageEnum.REQUEST_NOT_MATCH_REQUEST,INTERFACE_NAME+rpcRequest.getServiceName());
}
// getCode: service invoke fail
if(rpcResponce.getCode() == null || !rpcResponce.getCode().equals(RpcResponseCodeEnum.SUCCESS.getCode())) {
throw new RpcException(RpcErrorMessageEnum.SERVICE_INVOKATION_FAILURE,INTERFACE_NAME+rpcRequest.getServiceName());
}
}
}
-------------本文结束感谢您的阅读-------------