SOFA RPC源码解析之RPC代理机制

本文深入探讨SOFA RPC的代理机制,解释如何使用JDK动态代理和Javassist动态类库创建服务引用的代理对象。通过代理模式,本地方法调用被转换为远程服务调用,简化了开发者的操作。文中详细分析了JDKInvocationHandler和JavassistProxy的实现,展示了两者在源码层面的区别。
摘要由CSDN通过智能技术生成

1.SOFA RPC源码解析

1.1  RPC代理机制

        在SOFA RPC中,服务引用采用代理模式把本地方法调用转换为远程服务调用,从而使开发者像使用本地Java方法一样,使用远程服务,屏蔽了底层的网络通讯细节,使开发人员把精力集中在业务开发中。

        简单回顾一下代理模式,以便大家理解SOFA RPC中代理机制的实现方式。

        代理模式是常用的设计模式之一。当无法直接访问某个对象或访问某个对象存在困难时,可以通过一个代理对象来间接访问,为了保证客户端使用的透明性,所访问的真实对象与代理对象需要实现相同的接口。

        按照代理的创建时期,代理类可以分为两种:

        1.   静态代理:由程序员创建或特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了;

        2.   动态代理:在程序运行时,运用反射机制动态创建而成。

        在SOFABoot中,对于JVM服务类型的服务引用,即可以针对某个接口创建代理对象,也可以针对某个类创建代理对象。

        在SOFA RPC中,规定只能针对某个接口创建代理对象,所以采用动态代理方式为远程服务创建本地代理对象。如果被代理的对象为Java类,而不是接口,则在创建代理对象时,抛出异常,例如:

1.  The value of config consumer.interface[com.alipay.sofa.boot.examples.demo.rpc.bean.PersonServiceImpl2] is illegal,interfaceId must set interface class, not implement class

        在SOFA RPC中,主要有两种创建代理的方式:JDK动态代理机制和Javassist动态类库。

        在此补充说明一下,为了查看Proxy动态生成的代理对象的源文件,必须先导出字节码文件,然后通过反编译工具(如:jad)生成源文件。对于Proxy,导出字节码文件方式为在应用代码开始位置设置sun.misc.ProxyGenerator.saveGeneratedFiles为true:

1.  @SpringBootApplication
2.  @ImportResource({"classpath*:rpc-starter-example.xml" })
3.  public class SofaBootRpcDemoApplication {
4.   
5.      public static void main(String[] args)throws InterruptedException {
6.       
7.        System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true");
8.       
9.        ConfigurableApplicationContext ac =SpringApplication.run(SofaBootRpcDemoApplication.class, args);
10.          
11.  
12.     }
13. }

        注意,需要在工程根目录下,增加 com/sun/proxy目录,否则会报错如下:

1.  Exception in thread "main"java.lang.InternalError: I/O exception saving generatedfile:java.io.FileNotFoundException : com\sun\proxy\$Proxy0.class (系统找不到指定的路径。)
2.       atsun.misc.ProxyGenerator$1.run(ProxyGenerator.java:336 )
3.       atsun.misc.ProxyGenerator$1.run(ProxyGenerator.java:327 )
4.       at java.security.AccessController.doPrivileged( NativeMethod)
5.       atsun.misc.ProxyGenerator.generateProxyClass( ProxyGenerator.java:326)
6.       atjava.lang.reflect.Proxy$ProxyClassFactory.apply( Proxy.java:672)
7.       atjava.lang.reflect.Proxy$ProxyClassFactory.apply( Proxy.java:592)
8.       atjava.lang.reflect.WeakCache$Factory.get( WeakCache.java:244)
9.       atjava.lang.reflect.WeakCache.get(WeakCache.java:141 )
10.      atjava.lang.reflect.Proxy.getProxyClass0(Proxy.java:455 )
11.      atjava.lang.reflect.Proxy.newProxyInstance( Proxy.java:738)

 1.1.1 JDK动态代理

        提到JDK动态代理,大家一定想到java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口。

        1.  通过实现InvocationHandler接口,为代理对象提供调用处理器handler。当调用代理对象某个方法时,该方法调用将会被分发到handler的invoke方法,由其在调用目标对象的方法前后,进行一些额外处理。

        2.  通过Proxy类newProxyInstance方法,为实现某个接口的类创建代理对象。

        首先,看一下JDKProxy类的源码,该类对外提供了为指定接口动态创建代理对象的方法:

1.  @Extension("jdk")
2.  public class JDKProxy implements Proxy {
3.   
4.      @Override
5.      public <T> T getProxy(Class<T>interfaceClass, Invoker proxyInvoker) {
6.          InvocationHandler handler = new JDKInvocationHandler(interfaceClass,proxyInvoker);
7.          ClassLoader classLoader =ClassLoaderUtils.getCurrentClassLoader();
8.          T result = (T)java.lang.reflect.Proxy.newProxyInstance(classLoader,
9.              new Class[] { interfaceClass },handler);
10.         return result;
11.     }
12.  
13.     @Override
14.     public Invoker getInvoker(ObjectproxyObject) {
15.         return parseInvoker(proxyObject);
16.     }
17.  
18.     /**
19.      * Parse proxy invoker from proxy object
20.      *
21.      * @param proxyObject Proxy object
22.      * @return proxy invoker
23.      */
24.     public static Invoker parseInvoker(ObjectproxyObject) {
25.         InvocationHandler handler =java.lang.reflect.Proxy.getInvocationHandler(proxyObject);
26.         if (handler instanceofJDKInvocationHandler) {
27.             return ((JDKInvocationHandler)handler).getProxyInvoker();
28.         }
29.         return null;
30.     }
31. }

        getProxy方法主要处理逻辑如下:

        1.  根据接口类型和Invoker接口的实现类,创建JDKInvocationHandler实例;

        2.  调用Proxy类newProxyInstance方法,创建代理对象;

        在SOFA RPC中,com.alipay.sofa.rpc.proxy.jdk.JDKInvocationHandler类实现了InvocationHandler接口。

        JDKInvocationHandler类的源代码如下:

1.  public class JDKInvocationHandlerimplements InvocationHandler {
2.   
3.      /**
4.       * 代理类
5.       */
6.      private Class  proxyClass;
7.   
8.      /**
9.       * 代理调用器
10.      */
11.     private Invoker proxyInvoker;
12.  
13.     /**
14.      * Instantiates a new Jdk invocationhandler.
1
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

任性之闲来无事

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值