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

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/beyondself_77/article/details/80862238

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.
15.      *
16.      * @param proxyClass   the proxy class
17.      * @param proxyInvoker the proxy invoker
18.      */
19.     public JDKInvocationHandler(ClassproxyClass, Invoker proxyInvoker) {
20.         this.proxyClass = proxyClass;
21.         this.proxyInvoker = proxyInvoker;
22.     }
23.  
24.     @Override
25.     public Object invoke(Object proxy, Methodmethod, Object[] paramValues)
26.         throws Throwable {
27.         String methodName = method.getName();
28.         Class[] paramTypes =method.getParameterTypes();
29.         if("toString".equals(methodName) && paramTypes.length == 0) {
30.             return proxyInvoker.toString();
31.         } else if("hashCode".equals(methodName) && paramTypes.length == 0) {
32.             return proxyInvoker.hashCode();
33.         } else if("equals".equals(methodName) && paramTypes.length == 1) {
34.             Object another = paramValues[0];
35.             return proxy == another ||
36.                 (proxy.getClass().isInstance(another)&& proxyInvoker.equals(JDKProxy.parseInvoker(another)));
37.         }
38.         SofaRequest sofaRequest =MessageBuilder.buildSofaRequest(method.getDeclaringClass(),
39.             method, paramTypes, paramValues);
40.         SofaResponse response =proxyInvoker.invoke(sofaRequest);
41.         if (response.isError()) {
42.             throw newSofaRpcException(RpcErrorType.SERVER_UNDECLARED_ERROR, response.getErrorMsg());
43.         }
44.         Object ret = response.getAppResponse();
45.         if (ret instanceof Throwable) {
46.             throw (Throwable) ret;
47.         } else {
48.             if (ret == null) {
49.                 returnClassUtils.getDefaultArg(method.getReturnType());
50.             }
51.             return ret;
52.         }
53.     }
54.  
55.     /**
56.      * Gets proxy class.
57.      *
58.      * @return the proxy class
59.      */
60.     public Class getProxyClass() {
61.         return proxyClass;
62.     }
63.  
64.     /**
65.      * Gets proxy invoker.
66.      *
67.      * @return the proxy invoker
68.      */
69.     public Invoker getProxyInvoker() {
70.         return proxyInvoker;
71.     }
72. }

        JDKInvocationHandler类invoke方法主要处理逻辑如下:

        1.  本地方法调用封装成SofaRequest请求对象;

        2.  通过调用Invoker接口实现类DefaultClientProxyInvoker(该类继承了ClientProxyInvoker类,而ClientProxyInvoker类实现了Invoker接口)的invoke方法,以SofaRequest为参数,进行远程服务调用,并返回处理结果SofaResponse。

        3.  从SofaResponse对象中获取实际的远程服务的处理结果,并返回给本地客户端。

        在此,以SOFABoot自带的RPC案例sofaboot-sample-with-rpc为例,看看为com.alipay.sofa.boot.examples.demo.rpc.bean.PersonService接口创建的服务代理对象的源文件:

1.  importcom.alipay.sofa.boot.examples.demo.rpc.bean.PersonService;
2.  importjava.lang.reflect.InvocationHandler;
3.  import java.lang.reflect.Method;
4.  import java.lang.reflect.Proxy;
5.  importjava.lang.reflect.UndeclaredThrowableException;
6.   
7.  public final class $Proxy0 extendsProxy  implements PersonService
8.  {
9.    private static Method m1;
10.   private static Method m3;
11.   private static Method m0;
12.   private static Method m2;
13.  
14.   public $Proxy0(InvocationHandlerparamInvocationHandler)
15.     throws
16.   {
17.     super(paramInvocationHandler);
18.   }
19.  
20.   public final boolean equals(ObjectparamObject)
21.     throws
22.   {
23.     try
24.     {
25.       return ((Boolean)this.h.invoke(this, m1,new Object[] { paramObject })).booleanValue();
26.     }
27.     catch (RuntimeExceptionlocalRuntimeException)
28.     {
29.       throw localRuntimeException;
30.     }
31.     catch (Throwable localThrowable)
32.     {
33.     }
34.     throw newUndeclaredThrowableException(localThrowable);
35.   }
36.  
37.   publicfinal String sayName(String paramString)
38.     throws
39.   {
40.     try
41.     {
42.       return (String)this.h.invoke(this, m3,new Object[] { paramString });
43.     }
44.     catch (RuntimeExceptionlocalRuntimeException)
45.     {
46.       throw localRuntimeException;
47.     }
48.     catch (Throwable localThrowable)
49.     {
50.     }
51.     throw newUndeclaredThrowableException(localThrowable);
52.   }
53.  
54.   public final int hashCode()
55.     throws
56.   {
57.     try
58.     {
59.       return ((Integer)this.h.invoke(this, m0,null)).intValue();
60.     }
61.     catch (RuntimeExceptionlocalRuntimeException)
62.     {
63.       throw localRuntimeException;
64.     }
65.     catch (Throwable localThrowable)
66.     {
67.     }
68.     throw newUndeclaredThrowableException(localThrowable);
69.   }
70.  
71.   public final String toString()
72.     throws
73.   {
74.     try
75.     {
76.       return (String)this.h.invoke(this, m2,null);
77.     }
78.     catch (RuntimeException localRuntimeException)
79.     {
80.       throw localRuntimeException;
81.     }
82.     catch (Throwable localThrowable)
83.     {
84.     }
85.     throw newUndeclaredThrowableException(localThrowable);
86.   }
87.  
88.   static
89.   {
90.     try
91.     {
92.       m1 =Class.forName("java.lang.Object").getMethod("equals", newClass[] { Class.forName("java.lang.Object") });
93.       m3 =Class.forName("com.alipay.sofa.boot.examples.demo.rpc.bean.PersonService").getMethod("sayName",new Class[] { Class.forName("java.lang.String") });
94.       m0 = Class.forName("java.lang.Object").getMethod("hashCode",new Class[0]);
95.       m2 =Class.forName("java.lang.Object").getMethod("toString", newClass[0]);
96.       return;
97.     }
98.     catch (NoSuchMethodExceptionlocalNoSuchMethodException)
99.     {
100.       throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
101.     }
102.     catch (ClassNotFoundExceptionlocalClassNotFoundException)
103.     {
104.     }
105.     throw newNoClassDefFoundError(localClassNotFoundException.getMessage());
106.   }
107. }

        从上述代码可以看出,该代理对象继承了Proxy类,实现了PersonService接口。主要看一下代理对象对于PersonService接口的sayName方法实现方式。在sayName方法中,实际调用handler的invoke方法:

1.  (String)this.h.invoke(this, m3, newObject[] { paramString })

        此处h为JDKInvocationHandler实例。

        这样,当客户端调用实现了PersonService接口的代理对象的sayName方法时,实际上是调用JDKInvocationHandler类invoke方法,完成本地方法调用到远程服务调用的转换。JDKInvocationHandler类invoke方法的主要处理逻辑如上所述。

1.1.2 Javassist动态类库

        在SOFA RPC中,提供了另一种为远程服务创建本地代理对象的方式,即Javassist动态类库。

        Javassist是一款字节码编辑工具,可以直接编辑和生成Java字节码,以达到对.class文件进行动态修改的效果。关于Javassist,在此不详述,有兴趣的同学可以在网上搜索资料自行研究。

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

1.  @Extension("javassist")
2.  public class JavassistProxy implementsProxy {
3.   
4.      /**
5.       * Logger for this class
6.       */
7.      private static final Logger              LOGGER          =LoggerFactory.getLogger(JavassistProxy.class);
8.   
9.      private static AtomicInteger             counter         = new AtomicInteger();
10.  
11.     /**
12.      * 原始类和代理类的映射
13.      */
14.     protected final static Map<Class,Class> PROXY_CLASS_MAP = new ConcurrentHashMap<Class, Class>();
15.  
16.     @Override
17.     @SuppressWarnings("unchecked")
18.     public <T> T getProxy(Class<T>interfaceClass, Invoker proxyInvoker) {
19.         try {
20.             Class clazz =PROXY_CLASS_MAP.get(interfaceClass);
21.             if (clazz == null) {
22.                 //生成代理类
23.                 String interfaceName =ClassTypeUtils.getTypeStr(interfaceClass);
24.                 ClassPool mPool =ClassPool.getDefault();
25.                 mPool.appendClassPath(newLoaderClassPath(ClassLoaderUtils.getClassLoader(JavassistProxy.class)));
26.                 CtClass mCtc =mPool.makeClass(interfaceName + "_proxy_" +counter.getAndIncrement());
27.                 if(interfaceClass.isInterface()) {
28.                     mCtc.addInterface(mPool.get(interfaceName));
29.                 } else {
30.                     throw newIllegalArgumentException(interfaceClass.getName() + " is not aninterface");
31.                 }
32.  
33.                 // 继承 java.lang.reflect.Proxy
34.                 mCtc.setSuperclass(mPool.get(java.lang.reflect.Proxy.class.getName()));
35.                 CtConstructor constructor = newCtConstructor(null, mCtc);
36.                 constructor.setModifiers(Modifier.PUBLIC);
37.                 constructor.setBody("{super(new" + UselessInvocationHandler.class.getName() + "());}");
38.                 mCtc.addConstructor(constructor);
39.  
40.                 mCtc.addField(CtField.make("public" + Invoker.class.getCanonicalName() + " proxyInvoker = null;",
41.                     mCtc));
42.                 StringBuilder sb = null;
43.                 if (LOGGER.isDebugEnabled()) {
44.                     sb = new StringBuilder();
45.                 }
46.                 List<String> methodList =createMethod(interfaceClass);
47.                 for (String methodStr :methodList) {
48.                     mCtc.addMethod(CtMethod.make(methodStr,mCtc));
49.                     if(LOGGER.isDebugEnabled()) {
50.                         sb.append(methodStr).append("\n");
51.                     }
52.                 }
53.                 if (LOGGER.isDebugEnabled()) {
54.                     LOGGER.debug("javassistproxy of interface: {} \r\n{}", interfaceClass,
55.                         sb != null ?sb.toString() : "");
56.                 }
57.                 clazz = mCtc.toClass();
58.                 PROXY_CLASS_MAP.put(interfaceClass,clazz);
59.             }
60.             Object instance =clazz.newInstance();
61.             clazz.getField("proxyInvoker").set(instance,proxyInvoker);
62.             return (T) instance;
63.         } catch (Exception e) {
64.             throw newSofaRpcRuntimeException("", e);
65.         }
66.     }
67.  
68.     private List<String>createMethod(Class<?> interfaceClass) {
69.         Method[] methodAry =interfaceClass.getMethods();
70.         StringBuilder sb = newStringBuilder(512);
71.         List<String> resultList = newArrayList<String>();
72.         for (Method m : methodAry) {
73.             if(Modifier.isNative(m.getModifiers()) || Modifier.isFinal(m.getModifiers())) {
74.                 continue;
75.             }
76.             Class<?>[] mType =m.getParameterTypes();
77.             Class<?> returnType =m.getReturnType();
78.  
79.             sb.append(Modifier.toString(m.getModifiers()).replace("abstract","") + " " +
80.                 ClassTypeUtils.getTypeStr(returnType)+ " " + m.getName() + "( ");
81.             int c = 0;
82.  
83.             for (Class<?> mp : mType) {
84.                 sb.append(" " +mp.getCanonicalName() + " arg" + c + " ,");
85.                 c++;
86.             }
87.             sb.deleteCharAt(sb.length() - 1);
88.             sb.append(")");
89.             Class<?>[] exceptions =m.getExceptionTypes();
90.             if (exceptions.length > 0) {
91.                 sb.append(" throws");
92.                 for (Class<?> exception :exceptions) {
93.                     sb.append(exception.getCanonicalName()+ " ,");
94.                 }
95.                 sb =sb.deleteCharAt(sb.length() - 1);
96.             }
97.             sb.append("{");
98.  
99.             sb.append(" Class clazz =" + interfaceClass.getCanonicalName() + ".class;");
100.             sb.append(" String methodName= \"" + m.getName() + "\";");
101.             sb.append(" Class[] paramTypes= new Class[" + c + "];");
102.             sb.append(" Object[]paramValues = new Object[" + c + "];");
103.             for (int i = 0; i < c; i++) {
104.                 sb.append("paramValues["+ i + "] = ($w)$" + (i + 1) + ";");
105.                 sb.append("paramTypes["+ i + "] = " + mType[i].getCanonicalName() + ".class;");
106.             }
107.  
108.             sb.append(SofaRequest.class.getCanonicalName()+ " request = " +
109.                 MessageBuilder.class.getCanonicalName()+
110.                 ".buildSofaRequest(clazz,methodName, paramTypes, paramValues);");
111.             sb.append(SofaResponse.class.getCanonicalName()+ " response = " +
112.                 "proxyInvoker.invoke(request);");
113.             sb.append("if(response.isError()){");
114.             sb.append("  throw new " +SofaRpcException.class.getName() + "(" + RpcErrorType.class.getName()+
115.                 ".SERVER_UNDECLARED_ERROR,"+
116.                 "response.getErrorMsg());");
117.             sb.append("}");
118.  
119.             if (returnType.equals(void.class)){
120.                 sb.append("return;");
121.             } else {
122.                 sb.append("Object ret =response.getAppResponse();");
123.                 sb.append("if(retinstanceof " + Throwable.class.getName() + ") {");
124.                 sb.append("    throw (" + Throwable.class.getName() +") ret;");
125.                 sb.append("} else{");
126.                 sb.append("    return " + asArgument(returnType,"ret") + ";");
127.                 sb.append("}");
128.             }
129.  
130.             sb.append("}");
131.             resultList.add(sb.toString());
132.             sb.delete(0, sb.length());
133.         }
134.  
135.         // toString()
136.         sb.append("public StringtoString() {");
137.         sb.append("  return proxyInvoker.toString();");
138.         sb.append("}");
139.         resultList.add(sb.toString());
140.         // hashCode()
141.         sb.delete(0, sb.length());
142.         sb.append("public int hashCode(){");
143.         sb.append("  return proxyInvoker.hashCode();");
144.         sb.append("}");
145.         resultList.add(sb.toString());
146.         // equals()
147.         sb.delete(0, sb.length());
148.         sb.append("public booleanequals(Object obj) {");
149.         sb.append("  return this == obj ||(getClass().isInstance($1) " +
150.             "&&proxyInvoker.equals(" + JavassistProxy.class.getName() +".parseInvoker($1)));");
151.         sb.append("}");
152.         resultList.add(sb.toString());
153.         return resultList;
154.     }
155.  
156.     private String asArgument(Class<?>cl, String name) {
157.         if (cl.isPrimitive()) {
158.             if (Boolean.TYPE == cl) {
159.                 return name +"==null?false:((Boolean)" + name + ").booleanValue()";
160.             }
161.             if (Byte.TYPE == cl) {
162.                 return name +"==null?(byte)0:((Byte)" + name + ").byteValue()";
163.             }
164.             if (Character.TYPE == cl) {
165.                 return name +"==null?(char)0:((Character)" + name + ").charValue()";
166.             }
167.             if (Double.TYPE == cl) {
168.                 return name +"==null?(double)0:((Double)" + name + ").doubleValue()";
169.             }
170.             if (Float.TYPE == cl) {
171.                 return name +"==null?(float)0:((Float)" + name + ").floatValue()";
172.             }
173.             if (Integer.TYPE == cl) {
174.                 return name +"==null?(int)0:((Integer)" + name + ").intValue()";
175.             }
176.             if (Long.TYPE == cl) {
177.                 return name +"==null?(long)0:((Long)" + name + ").longValue()";
178.             }
179.             if (Short.TYPE == cl) {
180.                 return name +"==null?(short)0:((Short)" + name + ").shortValue()";
181.             }
182.             throw new RuntimeException(name +" is unknown primitive type.");
183.         }
184.         return "(" +ClassTypeUtils.getTypeStr(cl) + ")" + name;
185.     }
186.  
187.     @Override
188.     public Invoker getInvoker(ObjectproxyObject) {
189.         return parseInvoker(proxyObject);
190.     }
191.  
192.     /**
193.      * Parse proxy invoker from proxy object
194.      *
195.      * @param proxyObject Proxy object
196.      * @return proxy invoker
197.      */
198.     public static Invoker parseInvoker(ObjectproxyObject) {
199.         Field field;
200.         try {
201.             field =proxyObject.getClass().getField("proxyInvoker");
202.             if (field != null) {
203.                 if (!field.isAccessible()) {
204.                     field.setAccessible(true);
205.                 }
206.                 return (Invoker)field.get(proxyObject);
207.             } else {
208.                 return null;
209.             }
210.         } catch (Exception e) {
211.             return null;
212.         }
213.     }
214. }

        如上所示,在getProxy方法中,通过Javassist相关的API,根据接口类型和Invoker接口的实现类,动态创建代理对象的Java类文件,并编译成字节码格式的class文件。

        在此,还是以SOFABoot自带的RPC案例sofaboot-sample-with-rpc为例,看看为com.alipay.sofa.boot.examples.demo.rpc.bean.PersonService接口创建的服务代理对象的源文件:

1.  import com.alipay.sofa.rpc.core.exception.SofaRpcException;
2.  importcom.alipay.sofa.rpc.core.request.SofaRequest;
3.  importcom.alipay.sofa.rpc.core.response.SofaResponse;
4.  import com.alipay.sofa.rpc.invoke.Invoker;
5.  importcom.alipay.sofa.rpc.message.MessageBuilder;
6.  import com.alipay.sofa.rpc.proxy.javassist.JavassistProxy;
7.  importcom.alipay.sofa.rpc.proxy.javassist.UselessInvocationHandler;
8.  import java.lang.reflect.Proxy;
9.   
10. public class PersonService_proxy_0 extendsProxy
11.   implements PersonService
12. {
13.   public Invoker proxyInvoker = null;
14.  
15.   publicPersonService_proxy_0()
16.   {
17.     super(new UselessInvocationHandler());
18.   }
19.  
20.   public String sayName(String paramString)
21.   {
22.     PersonService localPersonService =PersonService.class;
23.     String str = "sayName";
24.     Class[] arrayOfClass = new Class[1];
25.     Object[] arrayOfObject = new Object[1];
26.     arrayOfObject[0] = paramString;
27.     arrayOfClass[0] = String.class;
28.     SofaRequest localSofaRequest =MessageBuilder.buildSofaRequest(localPersonService, str, arrayOfClass,arrayOfObject);
29.     SofaResponse localSofaResponse =this.proxyInvoker.invoke(localSofaRequest);
30.     if (localSofaResponse.isError())
31.       throw new SofaRpcException(199,localSofaResponse.getErrorMsg());
32.     Object localObject =localSofaResponse.getAppResponse();
33.     if ((localObject instanceof Throwable))
34.       throw ((Throwable)localObject);
35.     return (String)localObject;
36.   }
37.  
38.   public String toString()
39.   {
40.     return this.proxyInvoker.toString();
41.   }
42.  
43.   public int hashCode()
44.   {
45.     return this.proxyInvoker.hashCode();
46.   }
47.  
48.   public boolean equals(Object paramObject)
49.   {
50.     if ((this == paramObject) ||((!getClass().isInstance(paramObject)) ||(this.proxyInvoker.equals(JavassistProxy.parseInvoker(paramObject)))))
51.       break label42;
52.     tmpTernaryOp = false;
53.     label42: return true;
54.   }
55. }

        从上述代码可以看出,该代理对象继承了Proxy类,实现了PersonService接口。主要看一下代理对象对于PersonService接口的sayName方法实现方式。

        在sayName方法中,主要处理逻辑如下:

        1.  本地方法调用封装成SofaRequest请求对象;

        2.  通过调用Invoker接口实现类DefaultClientProxyInvoker(该类继承了ClientProxyInvoker类,而ClientProxyInvoker类实现了Invoker接口)的invoke方法,以SofaRequest为参数,进行远程服务调用,并返回处理结果SofaResponse。

        3.  从SofaResponse对象中获取实际的远程服务的处理结果,并返回给本地客户端。

1.1.3 总结

        通过比较JDK Proxy创建的代理对象和Javassist创建的代理对象的源码可以看出,其内部实现方式有些不同:

        1.  对于equals、hashCode、toString方法,JDK Proxy创建的代理对象通过反射机制调用java.lang.Object对象的equals、hashCode、toString方法;而Javassist创建的代理对象则直接调用proxyInvoker的equals、hashCode、toString方法;

        2.  对于服务接口的相关方法,如上述案例中PersonService接口的sayName方法,其把本地方法调用转换为远程服务调用的实现逻辑相同,但实现方式不同。JDK Proxy创建的代理对象在JDKInvocationHandler类invoke方法中实现,Javassist创建的代理对象则直接在接口方法中实现。

展开阅读全文

没有更多推荐了,返回首页