关于java:RPC实现原理之核心技术动态代理

60次阅读

共计 2512 个字符,预计需要花费 7 分钟才能阅读完成。

1. 动静代理调用流程

RPC 的调用对用户来讲是通明的,外部具体是如何实现呢?

核心技术采纳的就是动静代理,RPC 会主动给接口生成一个代理类,当咱们在我的项目中注入初始化接口的时候,运行过程中理论绑定的是这个接口生成的代理类。
在接口办法被调用的时候,它实际上是被生成代理类拦挡到了,这样就能够在生成的代理类外面,退出其余调用解决逻辑。

2. 为什么要退出动静代理

  1. 如果没有动静代理, 服务端大量的接口将不便于管理,须要大量的 if 判断,如果扩大了新的接口,须要更改调用逻辑,不利于扩大保护。
  2. 动静代理能够做到外部办法级拦挡,并且增加其余额定性能,比方连贯负载治理,权限管制,日志记录等等。

3. JDK 动静代理实现

  1. JDK 动静代理实现流程:
  2. 实现代码:

      public class JDKDynamicProxy {public static void main(String[] args){
                     // 构建代理器
                     JDKProxy proxy = new JDKProxy(new Teacher());
                     ClassLoader classLoader = JDKDynamicProxy.class.getClassLoader();
    
                     // 生成代理类
                     User user = (User) Proxy.newProxyInstance(classLoader, new Class[]{User.class}, proxy);
    
                     // 接口调用
                     System.out.println(user.job());
             }
             /**
              * 定义用户的接口
              */
             public interface User {String job();
             }
    
             /**
              * 理论的调用对象
              */
             public static class Teacher  {public String invoke(){return "i'm a Teacher";}
             }
    
             /**
              * 创立 JDK 动静代理类
              */
             public static class JDKProxy implements InvocationHandler {
                     private Object target;
    
                     JDKProxy(Object target) {this.target = target;}
    
                     @Override
                     public Object invoke(Object proxy, Method method, Object[] paramValues) {return ((Teacher)target).invoke();}
             }
     }

反编译生成的代理类能够晓得,代理类 $Proxy 外面会定义雷同签名的接口 (也就是下面代码 User 的 job 接口),而后外部会定义一个变量绑定 JDKProxy 代理对象,当调用 User.job 接口办法,本质上调用的是 JDKProxy.invoke() 办法,从而实现了接口的动静代理。

4. Cglib 动静代理实现

  1. 服务接口

    编写订单服务的下单接口:
      public class OrderService {
    
        /**
         * 下单接口
         */
        public String placeOrder(String userName) {System.out.println("用户:" + userName + "开始下单");
            return "胜利";
        }
    }
  2. 代理实现

     实现 MethodInterceptor 接口,重写 intercept 办法,能够追加校验逻辑、日志记录等性能。
    public class OrderServiceCglib implements MethodInterceptor {public Object getProxy(Object target) {Enhancer enhancer = new Enhancer();
            enhancer.setSuperclass(target.getClass());
            // 设置回调办法
            enhancer.setCallback(this);
            // 创立代理对象
            return enhancer.create();}
    
        /**
         * 实现 MethodInterceptor 接口中重写的办法
         */
        @Override
        public Object intercept(Object object, Method method, Object[] args, MethodProxy proxy) throws Throwable {System.out.println("校验下单参数:" + Arrays.asList(args));
            Object result = proxy.invokeSuper(object, args);
            System.out.println("记录下单日志后果:" + result);
            return result;
        }
    
    }

5. 开源动静代理技术解析

(1) Cglib 动静代理

Cglib 是一个弱小的、高性能的代码生成包,它宽泛被许多 AOP 框架应用,反对办法级别的拦挡。它是高级的字节码生成库,位于 ASM 之上,ASM 是低级的字节码生成工具,ASM 的应用对开发人员要求较高,相比拟来讲, ASM 性能更好。

(2) Byte Buddy 字节码加强库

Byte Buddy 是致力于解决字节码操作和 简化操作复杂性的开源框架。Byte Buddy 指标是将显式的字节码操作暗藏在一个类型平安的畛域特定语言背地。它属于后起之秀,在很多优良的我的项目中,像 Spring、Jackson 都用到了 Byte Buddy 来实现底层代理。相比 Javassist,Byte Buddy 提供了更容易操作的 API,编写的代码可读性更高。

(3) Javassist 动静代理

一个开源的剖析、编辑和创立 Java 字节码的类库。javassist 是 jboss 的一个子项目,它间接应用 java 编码的模式,不须要理解虚拟机指令,能够动静扭转类的构造,或者动静生成类。Javassist 的定位是可能操纵底层字节码,所以应用起来并不简略,Dubbo 框架的设计者为了谋求性能破费了不少精力去适配 javassist。

6. 开源动静代理性能比拟

Byte Buddy、CGLIB、Javassist、JDK 动静代理性能比拟:

综合后果:

单位是纳秒。大括号内代表的是样本标准差,综合后果:Byte Buddy > CGLIB > Javassist> JDK。

7. Dubbo 动静代理源码分析

  1. 源码调用流程
  2. 外围源码:

本文由 mirson 创作,心愿对大家有所帮忙, 谢谢!

正文完
 0