一、服务端Invoker
-
Invoker是一个代理,与dubbo中的SPI一样重要,在ServiceConfig中在调用export方法时会将一个invoker对象传递进去,分析下这个
private void doExportUrlsFor1Protocol(ProtocolConfig protocolConfig, List<URL> registryURLs) { //省略。。。 //TODO invoker -> 代理类 //proxyFactory是一个自适应扩展点,@Adaptive注解在方法上,因此是ProxyFactory$Adaptive //并且SPI扩展文件还有包装类 //最终 proxyFactory = new StubProxyFactoryWrapper(new JavassistProxyFactory()) //2. Invoker<?> invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, registryURL.addParameterAndEncoded(EXPORT_KEY, url.toFullString())); //元数据的委派 DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this); Exporter<?> exporter = protocol.export(wrapperInvoker); exporters.add(exporter); }
2. JavassistProxyFactory @Override public <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) { // TODO Wrapper cannot handle this scenario correctly: the classname contains '$' //这个方法会通过StringBuilder拼接代码动态的生成wrapper的实现类 并加载进jvm中 //3. final Wrapper wrapper = Wrapper.getWrapper(proxy.getClass().getName().indexOf('$') < 0 ? proxy.getClass() : type); //返回一个invoker, invoker.doInvoke() → wrapper.invokeMethod() → proxy.需要执行的方法() return new AbstractProxyInvoker<T>(proxy, type, url) { @Override protected Object doInvoke(T proxy, String methodName, Class<?>[] parameterTypes, Object[] arguments) throws Throwable { return wrapper.invokeMethod(proxy, methodName, parameterTypes, arguments); } }; }
3. public static Wrapper getWrapper(Class<?> c) { while (ClassGenerator.isDynamicClass(c)) // can not wrapper on dynamic class. { c = c.getSuperclass(); } if (c == Object.class) { return OBJECT_WRAPPER; } Wrapper ret = WRAPPER_MAP.get(c); if (ret == null) { //根据接口类型动态生成一个代理类 //这个代理类最重要的就是生成了 invokeMethod(proxy, methodName, parameterTypes, arguments) //执行的时候直接调用被代理类的方法(没有用反射)也就是直接 proxy(ServiceConfig中传入的接口实现类)执行自己的方法(); ret = makeWrapper(c); WRAPPER_MAP.put(c, ret); } return ret; }
-
按照流程继续走下去后会到DubboProtocol中的export方法
1. @Override public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException { URL url = invoker.getUrl(); // 要暴露的服务地址 String key = serviceKey(url); //将invoker封装为DubboExporter DubboExporter<T> exporter = new DubboExporter<T>(invoker, key, exporterMap); //缓存起来,后续给客户端调用 exporterMap.put(key, exporter); //省略。。。 return exporter; }