构建客户端源码解析(3)

勿忘初心2018-11-18 11:37

此文已由作者赵计刚薪授权网易云社区发布。

欢迎访问网易云社区,了解更多网易技术产品运营经验。


之后对DubboInvoker实例进行filter链的包装。

ConsumerContextFilter->FutureFilter->MonitorFilter->DubboInvoker.

最后将包装后的Invoker实例包装为InvokerDelegete实例。最后的最后,我们的终极目的:初始化RegistryDirectory的两个属性:

Map<String, List<Invoker<T>>> methodInvokerMap={
sayHello=[provider1的RegistryDirectory$InvokerDelegete实例, provider2的RegistryDirectory$InvokerDelegete实例], *=[provider1的RegistryDirectory$InvokerDelegete实例, provider2的RegistryDirectory$InvokerDelegete实例]}

Map<String, Invoker<T>> urlInvokerMap={dubbo://10.10.10.10:20880/com.alibaba.dubbo.demo.DemoService?anyhost=true&application=demo-consumer&check=false&dubbo=2.0.0&generic=false&interface=com.alibaba.dubbo.demo.DemoService&methods=sayHello&pid=25267&register.ip=10.10.10.10&remote.timestamp=1510225334486&side=consumer&timestamp=1510225913509
=
provider1的RegistryDirectory$InvokerDelegete实例, dubbo://10.211.55.5:20880/com.alibaba.dubbo.demo.DemoService?anyhost=true&application=demo-consumer&check=false&dubbo=2.5.7&generic=false&interface=com.alibaba.dubbo.demo.DemoService&methods=sayHello&pid=25267&register.ip=10.10.10.10&remote.timestamp=1510225244315&revision=2.5.7&side=consumer&timestamp=1510225913509=provider2的RegistryDirectory$InvokerDelegete实例}

到此为止,订阅就完成了。现在来看RegistryProtocol.doRefer的最后一行代码:return cluster.join(directory)

这里的cluster是Cluster$Adaptive实例:

 1 public class Cluster$Adaptive implements com.alibaba.dubbo.rpc.cluster.Cluster {
 2     public com.alibaba.dubbo.rpc.Invoker join(com.alibaba.dubbo.rpc.cluster.Directory arg0) throws com.alibaba.dubbo.rpc.RpcException {
 3         if (arg0 == null)
 4             throw new IllegalArgumentException("com.alibaba.dubbo.rpc.cluster.Directory argument == null");
 5         if (arg0.getUrl() == null)
 6             throw new IllegalArgumentException("com.alibaba.dubbo.rpc.cluster.Directory argument getUrl() == null");
 7         com.alibaba.dubbo.common.URL url = arg0.getUrl();
 8         String extName = url.getParameter("cluster", "failover");
 9         if (extName == null)
10             throw new IllegalStateException("Fail to get extension(com.alibaba.dubbo.rpc.cluster.Cluster) name from url(" + url.toString() + ") use keys([cluster])");
11         com.alibaba.dubbo.rpc.cluster.Cluster extension = (com.alibaba.dubbo.rpc.cluster.Cluster) ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.cluster.Cluster.class).getExtension(extName);
12         return extension.join(arg0);
13     }
14 }

这里的extName="failover",这里会进行aop:MockClusterWrapper包装FailoverCluster。

 1 public class MockClusterWrapper implements Cluster {
 2     private Cluster cluster;
 3 
 4     public MockClusterWrapper(Cluster cluster) {
 5         this.cluster = cluster;
 6     }
 7 
 8     public <T> Invoker<T> join(Directory<T> directory) throws RpcException {
 9         return new MockClusterInvoker<T>(directory,
10                 this.cluster.join(directory));
11     }
12 }

这里的cluster是FailoverCluster实例。

 1 /**
 2  * 失败转移,当出现失败,重试其它服务器,通常用于读操作,但重试会带来更长延迟。
 3  */
 4 public class FailoverCluster implements Cluster {
 5     public final static String NAME = "failover";
 6 
 7     public <T> Invoker<T> join(Directory<T> directory) throws RpcException {
 8         return new FailoverClusterInvoker<T>(directory);
 9     }
10 }
1     public FailoverClusterInvoker(Directory<T> directory) {
2         super(directory);
3     }

这里实际上就是创建一个FailoverClusterInvokers实例,通过其父类AbstractClusterInvoker存储属性。

最后创建一个MockClusterInvoker实例:

1     private final Directory<T> directory;
2     private final Invoker<T> invoker;
3 
4     public MockClusterInvoker(Directory<T> directory, Invoker<T> invoker) {
5         this.directory = directory;
6         this.invoker = invoker;
7     }

到此为止,下边的第一行代码就结束了!最终得到一个MockClusterInvoker实例:

  • directory=RegistryDirectory实例:
  • invoker=FailoverClusterInvokers实例(该实例中又包含一个Directory<T> directory属性,值为上述的RegistryDirectory实例)
1     private T createProxy(Map<String, String> map) {
2         ...
3         if (urls.size() == 1) {
4             invoker = refprotocol.refer(interfaceClass, urls.get(0));
5         } 
6         ...
7         // 创建服务代理
8         return (T) proxyFactory.getProxy(invoker);
9     }

 

二 使用ProxyFactory创建代理

1 (T) proxyFactory.getProxy(invoker)

上述的proxyFactory是ProxyFactory$Adaptive实例,其getProxy内部最终得到是一个被StubProxyFactoryWrapper包装后的JavassistProxyFactory。直接来看JavassistProxyFactory.getProxy方法

1     public <T> T getProxy(Invoker<T> invoker, Class<?>[] interfaces) {
2         return (T) Proxy.getProxy(interfaces).newInstance(new InvokerInvocationHandler(invoker));
3     }
  • invoker:MockClusterInvoker实例
  • interfaces:[interface com.alibaba.dubbo.demo.DemoService, interface com.alibaba.dubbo.rpc.service.EchoService]

注意这里的Proxy不是jdk的,而是dubbo的。

Proxy.getProxy(interfaces)

 1     public static Proxy getProxy(ClassLoader cl, Class<?>... ics) {
 2         ...
 3         Proxy proxy = null;
 4         ...
 5         // create ProxyInstance class.
 6         String pcn = pkg + ".proxy" + id;
 7         ccp.setClassName(pcn);
 8         ccp.addField("public static java.lang.reflect.Method[] methods;");
 9         ccp.addField("private " + InvocationHandler.class.getName() + " handler;");
10         ccp.addConstructor(Modifier.PUBLIC, new Class<?>[]{InvocationHandler.class}, new Class<?>[0], "handler=$1;");
11         ccp.addDefaultConstructor();
12         Class<?> clazz = ccp.toClass();
13         clazz.getField("methods").set(null, methods.toArray(new Method[0]));
14             
15         // create Proxy class.
16         String fcn = Proxy.class.getName() + id;
17         ccm = ClassGenerator.newInstance(cl);
18         ccm.setClassName(fcn);
19         ccm.addDefaultConstructor();
20         ccm.setSuperClass(Proxy.class);
21         ccm.addMethod("public Object newInstance(" + InvocationHandler.class.getName() + " h){ return new " + pcn + "($1); }");
22         Class<?> pc = ccm.toClass();
23         proxy = (Proxy) pc.newInstance();
24         ...
25         return proxy;
26     }

从代码来看,会生成两个Class对象:pc是创建代理类的工厂类;clazz是真实对象的代理类。最终返回的proxy是如下Proxy0对象;之后调用了Proxy0.newInstance(InvocationHandler paramInvocationHandler)方法:创建出了proxy0对象,并初始化了其中的InvocationHandler handler对象为InvokerInvocationHandler。

最终会生成两个类:(这两个类都是笔者都是直接导出.class文件之后通过jd-gui反编译出来的)。

工厂类

1 package com.alibaba.dubbo.common.bytecode;
2 
3 import java.lang.reflect.InvocationHandler;
4 
5 public class Proxy0 extends Proxy {
6     public Object newInstance(InvocationHandler paramInvocationHandler) {
7         return new proxy0(paramInvocationHandler);
8     }
9 }

真实对象代理类

 1 package com.alibaba.dubbo.common.bytecode;
 2 
 3 import com.alibaba.dubbo.demo.DemoService;
 4 import com.alibaba.dubbo.rpc.service.EchoService;
 5 import java.lang.reflect.InvocationHandler;
 6 import java.lang.reflect.Method;
 7 
 8 public class proxy0 implements EchoService, DemoService {
 9     public static Method[] methods;
10     private InvocationHandler handler;
11 
12     public String sayHello(String paramString) {
13         Object[] arrayOfObject = new Object[1];
14         arrayOfObject[0] = paramString;
15         Object localObject = this.handler.invoke(this, methods[0], arrayOfObject);
16         return (String) localObject;
17     }
18 
19     public Object $echo(Object paramObject) {
20         Object[] arrayOfObject = new Object[1];
21         arrayOfObject[0] = paramObject;
22         Object localObject = this.handler.invoke(this, methods[1], arrayOfObject);
23         return (Object) localObject;
24     }
25 
26     public proxy0() {
27     }
28 
29     public proxy0(InvocationHandler paramInvocationHandler) {
30         this.handler = paramInvocationHandler;
31     }
32 }

上边的methods数组实际上已经包含了两个元素:

[public abstract java.lang.String com.alibaba.dubbo.demo.DemoService.sayHello(java.lang.String),

public abstract java.lang.Object com.alibaba.dubbo.rpc.service.EchoService.$echo(java.lang.Object)]

如上所示,我们最终返回的代理对象其实是一个proxy0对象,当我们调用其sayHello方法时,其调用内部的handler.invoke方法。

 1 public class InvokerInvocationHandler implements InvocationHandler {
 2     private final Invoker<?> invoker;
 3 
 4     public InvokerInvocationHandler(Invoker<?> handler) {
 5         this.invoker = handler;
 6     }
 7 
 8     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
 9         String methodName = method.getName();
10         Class<?>[] parameterTypes = method.getParameterTypes();
11         if (method.getDeclaringClass() == Object.class) {
12             return method.invoke(invoker, args);
13         }
14         if ("toString".equals(methodName) && parameterTypes.length == 0) {
15             return invoker.toString();
16         }
17         if ("hashCode".equals(methodName) && parameterTypes.length == 0) {
18             return invoker.hashCode();
19         }
20         if ("equals".equals(methodName) && parameterTypes.length == 1) {
21             return invoker.equals(args[0]);
22         }
23         return invoker.invoke(new RpcInvocation(method, args)).recreate();
24     }
25 
26 }

这里的invoke是上述的MockClusterInvoker实例。

到此为止,DemoService demoService = (DemoService) context.getBean("demoService"); 该行代码就结束了。最终得到的demoService是一个proxy0实例(是一个代理)!


免费体验云安全(易盾)内容安全、验证码等服务

更多网易技术、产品、运营经验分享请点击