勿忘初心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®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实例(是一个代理)!
更多网易技术、产品、运营经验分享请点击。