此文已由作者赵计刚薪授权网易云社区发布。
欢迎访问网易云社区,了解更多网易技术产品运营经验。
之后对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®ister.ip=10.10.10.10&remote.timestamp=1510225334486&side=consumer×tamp=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®ister.ip=10.10.10.10&remote.timestamp=1510225244315&revision=2.5.7&side=consumer×tamp=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实例:
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 }
注意这里的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实例(是一个代理)!
更多网易技术、产品、运营经验分享请点击。