分布式系统架构时代,RPC框架你一定不会陌生。目前主流的RPC框架有 dubbo、thrift、motan、grpc等。
消费端(RPC Consumer)通常只有服务接口定义,接口的业务逻辑实现部署在生产端(RPC Provider),服务调用一般是采用动态代理方式,通过Proxy创建一个代理类,借助增强方式完成网络的远程调用,获取执行结果。
这里有两个关键点:
1、如何实现一个通用的代理类?
2、如何在消费端动态注入接口的代理对象?
如何实现一个通用的代理类?
目前动态代理的实现方案有很多种,如JDK 动态代理、Cglib、Javassist、ASM、Byte Buddy等
JDK 动态代理的代理类是运行时通过字节码生成的,我们通过Proxy.newProxyInstance方法获取的接口实现类就是这个字节码生成的代理类
定义代理类RpcInvocationHandler
,继承InvocationHandler
接口,并重写invoke()方法。
public class RpcInvocationHandler implements InvocationHandler {
private final String serviceVersion;
private final long timeout;
public RpcInvocationHandler(String serviceVersion, long timeout) {
this.serviceVersion = serviceVersion;
this.timeout = timeout;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) {
// todo
// 1、封装RpcProtocol对象
// 2、对象编码
// 3、发送请求到服务端
// 4、获取返回结果
// 模拟生成一个订单号
Long orderId = Long.valueOf(new Random().nextInt(100));
String s = String.format("【RpcInvocationHandler】 调用方法:%s , 参数:%s ,订单id:%d", method.getName(), JSON.toJSONString(args), orderId);
System.out.println(s);
return orderId;
}
如何在消费端动态注入接口的代理对象?
构造一个自定义Bean,并对该Bean下执行的所有方法拦截,增加额外处理逻辑。
OrderService
是一个订单接口类,client端没有该接口的实现类。
定义注解@RpcReference
,用于描述代理类的参数信息。
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@Autowired
public @interface RpcReference {
String serviceVersion() default "1.0";
long timeout() default 5000;
}
Spring 的 FactoryBean 接口可以帮助我们实现自定义的 Bean,FactoryBean 是一种特殊的工厂 Bean,通过 getObject() 方法返回对象,而并不是 FactoryBean 本身。
public class RpcReferenceBean implements FactoryBean<Object> {
private Class<?> interfaceClass;
private String serviceVersion;
private long timeout;
private Object object;
@Override
public Object getObject() throws Exception {
return object;
}