/* org.apache.dubbo.config.bootstrap.DubboBootstrap#start */ public DubboBootstrap start() { if (started.compareAndSet(false, true)) { //初始化 initialize(); if (logger.isInfoEnabled()) { logger.info(NAME + " is starting..."); } // 暴露dubbo服务(<dubbo:service />注册到注册表) exportServices(); // Not only provider register if (!isOnlyRegisterProvider() || hasExportedServices()) { // 2. export MetadataService exportMetadataService(); //3. Register the local ServiceInstance if required registerServiceInstance(); } //引用dubbo服务(<dubbo:reference /> 创建代理) referServices(); if (logger.isInfoEnabled()) { logger.info(NAME + " has started."); } } return this; }
DubboBootStrap.referServices():本地创建远程引用代理对象
/* org.apache.dubbo.config.bootstrap.DubboBootstrap#referServices */ private void referServices() { if (cache == null) { cache = ReferenceConfigCache.getCache(); } configManager.getReferences().forEach(rc -> { // 与alibaba版本的ReferenceConfig兼容,Apache是ReferenceBean类型 ReferenceConfig referenceConfig = (ReferenceConfig) rc; referenceConfig.setBootstrap(this); //<dubbo:reference init="true"/>立即加载,默认为false // 懒加载,延迟到依赖注入时ReferenceBean.getObject() if (rc.shouldInit()) { //异步 if (referAsync) { CompletableFuture<Object> future = ScheduledCompletableFuture.submit( executorRepository.getServiceExporterExecutor(), () -> cache.get(rc) ); asyncReferringFutures.add(future); } else { //同步 cache.get(rc); } } }); }
<dubbo:reference init="true" />才会立即加载,默认false,懒加载:需要使用时才会加载,实现方式:
ReferenceBean是FactoryBean类型,依赖注入时,调用ReferenceBean.getObject()生成一个代理类。
Reference.getObject():获取Service的引用
/* org.apache.dubbo.config.spring.ReferenceBean#getObject */ public Object getObject() { return get(); } /* org.apache.dubbo.config.ReferenceConfig#get */ public synchronized T get() { if (destroyed) { throw new IllegalStateException("The invoker of ReferenceConfig(" + url + ") has already destroyed!"); } if (ref == null) { //初始化 init(); } return ref; }
init():初始化属性,并且校验,最后根据属性注册到注册表,本地生成接口的代理类
public synchronized void init() { if (initialized) { return; } if (bootstrap == null) { bootstrap = DubboBootstrap.getInstance(); bootstrap.init(); } //检查并更新子设置 checkAndUpdateSubConfigs(); //检查若配置了local或stub,localClass或stubClass必须是interfaceClass的子类 checkStubAndLocal(interfaceClass); //检查熔断接口 ConfigValidationUtils.checkMock(interfaceClass, this); // map初始化一些属性,用途:设置到serviceMetadata(元数据)中;生成consumerUrl // map.put("init","false") // map.put("side","consumer") // map.put("application","dubbo-consumer") // map.put("register.ip","192.168.56.1") // map.put("release","2.7.5") // map.put("methods","insertUser,updateUser") // map.put("sticky","false") // map.put("dubbo","2.0.2") // map.put("pid","8748") // map.put("interface","org.study.service.UserService") // map.put("timestamp","1584282015078") Map<String, String> map = new HashMap<String, String>(); map.put(SIDE_KEY, CONSUMER_SIDE); ReferenceConfigBase.appendRuntimeParameters(map); if (!ProtocolUtils.isGeneric(generic)) { String revision = Version.getVersion(interfaceClass, version); if (revision != null && revision.length() > 0) { map.put(REVISION_KEY, revision); } String[] methods = Wrapper.getWrapper(interfaceClass).getMethodNames(); if (methods.length == 0) { logger.warn("No method found in service interface " + interfaceClass.getName()); map.put(METHODS_KEY, ANY_VALUE); } else { map.put(METHODS_KEY, StringUtils.join(new HashSet<String>(Arrays.asList(methods)), COMMA_SEPARATOR)); } } map.put(INTERFACE_KEY, interfaceName); AbstractConfig.appendParameters(map, getMetrics()); AbstractConfig.appendParameters(map, getApplication()); AbstractConfig.appendParameters(map, getModule()); // remove 'default.' prefix for configs from ConsumerConfig // appendParameters(map, consumer, Constants.DEFAULT_KEY); AbstractConfig.appendParameters(map, consumer); AbstractConfig.appendParameters(map, this); MetadataReportConfig metadataReportConfig = getMetadataReportConfig(); if (metadataReportConfig != null && metadataReportConfig.isValid()) { map.putIfAbsent(METADATA_KEY, REMOTE_METADATA_STORAGE_TYPE); } Map<String, AsyncMethodInfo> attributes = null; if (CollectionUtils.isNotEmpty(getMethods())) { attributes = new HashMap<>(); for (MethodConfig methodConfig : getMethods()) { AbstractConfig.appendParameters(map, methodConfig, methodConfig.getName()); String retryKey = methodConfig.getName() + ".retry"; if (map.containsKey(retryKey)) { String retryValue = map.remove(retryKey); if ("false".equals(retryValue)) { map.put(methodConfig.getName() + ".retries", "0"); } } AsyncMethodInfo asyncMethodInfo = AbstractConfig.convertMethodConfig2AsyncInfo(methodConfig); if (asyncMethodInfo != null) { // consumerModel.getMethodModel(methodConfig.getName()).addAttribute(ASYNC_KEY, asyncMethodInfo); attributes.put(methodConfig.getName(), asyncMethodInfo); } } } String hostToRegistry = ConfigUtils.getSystemProperty(DUBBO_IP_TO_REGISTRY); if (StringUtils.isEmpty(hostToRegistry)) { hostToRegistry = NetUtils.getLocalHost(); } else if (isInvalidLocalHost(hostToRegistry)) { throw new IllegalArgumentException("Specified invalid registry ip from property:" + DUBBO_IP_TO_REGISTRY + ", value:" + hostToRegistry); } map.put(REGISTER_IP_KEY, hostToRegistry); //map数据放入到元数据中 serviceMetadata.getAttachments().putAll(map); //创建引用代理,注册到注册表(建立zookeeper的znode) ref = createProxy(map); //设置到元数据中 serviceMetadata.setTarget(ref); serviceMetadata.addAttribute(PROXY_CLASS_REF, ref); ConsumerModel consumerModel = repository.lookupReferredService(serviceMetadata.getServiceKey()); consumerModel.setProxyObject(ref); consumerModel.init(attributes); //修改哨兵位,已初始化 initialized = true; //后置持利器执行等 // dispatch a ReferenceConfigInitializedEvent since 2.7.4 dispatch(new ReferenceConfigInitializedEvent(this, invoker)); }
ref = createProxy(map):创建利用注册表,创建本地代理实例
private T createProxy(Map<String, String> map) { if (shouldJvmRefer(map)) { //injvm,jvm内的互相调用 URL url = new URL(LOCAL_PROTOCOL, LOCALHOST_VALUE, 0, interfaceClass.getName()).addParameters(map); invoker = REF_PROTOCOL.refer(interfaceClass, url); if (logger.isInfoEnabled()) { logger.info("Using injvm service " + interfaceClass.getName()); } } else { //jvm外调用 urls.clear(); if (url != null && url.length() > 0) { // user specified URL, could be peer-to-peer address, or register center's address. //<dubbo:reference url="*"/> 自定义url String[] us = SEMICOLON_SPLIT_PATTERN.split(url); if (us != null && us.length > 0) { for (String u : us) { URL url = URL.valueOf(u); if (StringUtils.isEmpty(url.getPath())) { url = url.setPath(interfaceName); } if (UrlUtils.isRegistry(url)) { urls.add(url.addParameterAndEncoded(REFER_KEY, StringUtils.toQueryString(map))); } else { urls.add(ClusterUtils.mergeUrl(url, map)); } } } } else { // assemble URL from register center's configuration // 未自定义url、自动生成url //注册中心地址RegisteyUrl:registry://mcip:2291/org.apache.dubbo.registry.RegistryService?application=dubbo-consumer&backup=mcip:2292,mcip:2293&dubbo=2.0.2&pid=8748®istry=zookeeper&release=2.7.5×tamp=1584282824127 if (!LOCAL_PROTOCOL.equalsIgnoreCase(getProtocol())) { checkRegistry(); List<URL> us = ConfigValidationUtils.loadRegistries(this, false); if (CollectionUtils.isNotEmpty(us)) { for (URL u : us) { URL monitorUrl = ConfigValidationUtils.loadMonitor(this, u); if (monitorUrl != null) { map.put(MONITOR_KEY, URL.encode(monitorUrl.toFullString())); } urls.add(u.addParameterAndEncoded(REFER_KEY, StringUtils.toQueryString(map))); } } if (urls.isEmpty()) { throw new IllegalStateException("No such any registry to reference " + interfaceName + " on the consumer " + NetUtils.getLocalHost() + " use dubbo version " + Version.getVersion() + ", please config <dubbo:registry address="..." /> to your spring config."); } } } if (urls.size() == 1) { //注册中心只有一个时 invoker = REF_PROTOCOL.refer(interfaceClass, urls.get(0)); } else { //注册中心多个时 //获取所有的远程服务地址 List<Invoker<?>> invokers = new ArrayList<Invoker<?>>(); URL registryURL = null; for (URL url : urls) { invokers.add(REF_PROTOCOL.refer(interfaceClass, url)); if (UrlUtils.isRegistry(url)) { registryURL = url; // use last registry url } } if (registryURL != null) { // registry url is available // for multi-subscription scenario, use 'zone-aware' policy by default URL u = registryURL.addParameterIfAbsent(CLUSTER_KEY, ZoneAwareCluster.NAME); // The invoker wrap relation would be like: ZoneAwareClusterInvoker(StaticDirectory) -> FailoverClusterInvoker(RegistryDirectory, routing happens here) -> Invoker invoker = CLUSTER.join(new StaticDirectory(u, invokers)); } else { // not a registry url, must be direct invoke. invoker = CLUSTER.join(new StaticDirectory(invokers)); } } } if (shouldCheck() && !invoker.isAvailable()) { throw new IllegalStateException("Failed to check the status of the service " + interfaceName + ". No provider available for the service " + (group == null ? "" : group + "/") + interfaceName + (version == null ? "" : ":" + version) + " from the url " + invoker.getUrl() + " to the consumer " + NetUtils.getLocalHost() + " use dubbo version " + Version.getVersion()); } if (logger.isInfoEnabled()) { logger.info("Refer dubbo service " + interfaceClass.getName() + " from url " + invoker.getUrl()); } /** * @since 2.7.0 * ServiceData Store */ String metadata = map.get(METADATA_KEY); WritableMetadataService metadataService = WritableMetadataService.getExtension(metadata == null ? DEFAULT_METADATA_STORAGE_TYPE : metadata); if (metadataService != null) { URL consumerURL = new URL(CONSUMER_PROTOCOL, map.remove(REGISTER_IP_KEY), 0, map.get(INTERFACE_KEY), map); metadataService.publishServiceDefinition(consumerURL); } // 创建服务代理,默认javassist方式 return (T) PROXY_FACTORY.getProxy(invoker, ProtocolUtils.isGeneric(generic)); }
invoker = REF_PROTOCOL.refer(interfaceClass, urls.get(0)):生成invoker,实际类型MockClusterInvoker
/* org.apache.dubbo.registry.integration.RegistryProtocol#refer */ public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException { //生成注册中心地址RegistryUrl //zookeeper://mcip:2291/org.apache.dubbo.registry.RegistryService?application=dubbo-consumer&backup=mcip:2292,mcip:2293&dubbo=2.0.2&pid=8748&refer=application%3Ddubbo-consumer%26dubbo%3D2.0.2%26init%3Dfalse%26interface%3Dorg.study.service.UserService%26methods%3DgetUserById%2Cupdate%2Cinsert%2CtransactionalTest%2CgetUserByUserId%2Cdelete%26pid%3D8748%26register.ip%3D192.168.56.1%26release%3D2.7.5%26side%3Dconsumer%26sticky%3Dfalse%26timestamp%3D1584282015078&release=2.7.5×tamp=1584282824127 url = getRegistryUrl(url); Registry registry = registryFactory.getRegistry(url); if (RegistryService.class.equals(type)) { //RegistryService的底层类,直接创建代理 return proxyFactory.getInvoker((T) registry, type, url); } // 前面的map,内含11个参数 Map<String, String> qs = StringUtils.parseQueryString(url.getParameterAndDecoded(REFER_KEY)); String group = qs.get(GROUP_KEY); if (group != null && group.length() > 0) { //group不为空 if ((COMMA_SPLIT_PATTERN.split(group)).length > 1 || "*".equals(group)) { return doRefer(getMergeableCluster(), registry, type, url); } } //创建invoker return doRefer(cluster, registry, type, url); } private <T> Invoker<T> doRefer(Cluster cluster, Registry registry, Class<T> type, URL url) { RegistryDirectory<T> directory = new RegistryDirectory<T>(type, url); directory.setRegistry(registry); directory.setProtocol(protocol); // 属性map,11个属性 Map<String, String> parameters = new HashMap<String, String>(directory.getConsumerUrl().getParameters()); //利用map中属性,生成订阅url,consumerUrl //consumer://192.168.56.1/org.study.service.UserService?application=dubbo-consumer&dubbo=2.0.2&init=false&interface=org.study.service.UserService&methods=getUserById,update,insert,transactionalTest,getUserByUserId,delete&pid=8748&release=2.7.5&side=consumer&sticky=false×tamp=1584282015078 URL subscribeUrl = new URL(CONSUMER_PROTOCOL, parameters.remove(REGISTER_IP_KEY), 0, type.getName(), parameters); if (directory.isShouldRegister()) { directory.setRegisteredConsumerUrl(subscribeUrl); //注册到zookeeper中心 //实际创建节点:/dubbo/org.study.service.UserService/consumers/consumer%3A%2F%2F192.168.56.1%2Forg.study.service.UserService%3Fapplication%3Ddubbo-consumer%26category%3Dconsumers%26check%3Dfalse%26dubbo%3D2.0.2%26init%3Dfalse%26interface%3Dorg.study.service.UserService%26methods%3DgetUserById%2Cupdate%2Cinsert%2CtransactionalTest%2CgetUserByUserId%2Cdelete%26pid%3D8748%26release%3D2.7.5%26side%3Dconsumer%26sticky%3Dfalse%26timestamp%3D1584282015078 registry.register(directory.getRegisteredConsumerUrl()); } directory.buildRouterChain(subscribeUrl); //向服务器发送订阅请求 //创建三个目录节点(已存在不创建)/dubbo/interface/providers、routers、configurators //并扫描目录节点下的子节点,找到了providers directory.subscribe(toSubscribeUrl(subscribeUrl)); //生成一个url //里面包含interface-->registryUrl(zookeeper cluster leader node : zookeeper的集群的主节点) //interface-->providerUrl(上面subscribe,扫描providers目录下url时找到的) Invoker<T> invoker = cluster.join(directory); List<RegistryProtocolListener> listeners = findRegistryProtocolListeners(url); if (CollectionUtils.isEmpty(listeners)) { return invoker; } RegistryInvokerWrapper<T> registryInvokerWrapper = new RegistryInvokerWrapper<>(directory, cluster, invoker, subscribeUrl); for (RegistryProtocolListener listener : listeners) { listener.onRefer(this, registryInvokerWrapper); } return registryInvokerWrapper; }
return (T) PROXY_FACTORY.getProxy(invoker, ProtocolUtils.isGeneric(generic)):创建代理实例
/* org.apache.dubbo.rpc.proxy.javassist.JavassistProxyFactory#getProxy */ public <T> T getProxy(Invoker<T> invoker, Class<?>[] interfaces) { return (T) Proxy.getProxy(interfaces).newInstance(new InvokerInvocationHandler(invoker)); }
总结:
1、与service不同Reference采用延迟加载,使用时才会加载ref引用生成代理类
2、ReferenceBean实际是一个FactoryBean,接口绑定技术,与mybatis中接口映射器类似。
3、reference生成代理实例,不仅会扫描注册表对应接口下的providers,还会创建consumers目录,应该是为了监控。
二、RPC调用
InvokerInvocationHandler.invoke():代理实例的方法执行
/* org.apache.dubbo.rpc.proxy.InvokerInvocationHandler#invoke */ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //Object的方法,直接调用本地 //其他方法RPC if (method.getDeclaringClass() == Object.class) { return method.invoke(invoker, args); } String methodName = method.getName(); Class<?>[] parameterTypes = method.getParameterTypes(); if (parameterTypes.length == 0) { if ("toString".equals(methodName)) { return invoker.toString(); } else if ("$destroy".equals(methodName)) { invoker.destroy(); return null; } else if ("hashCode".equals(methodName)) { return invoker.hashCode(); } } else if (parameterTypes.length == 1 && "equals".equals(methodName)) { return invoker.equals(args[0]); } //封装一个RpcInvocation实例其实就是request //RpcInvocation记录RPC调用信息,interface-method(args) RpcInvocation rpcInvocation = new RpcInvocation(method, invoker.getInterface().getName(), args); //记录serviceKey group+interface+version String serviceKey = invoker.getUrl().getServiceKey(); rpcInvocation.setTargetServiceUniqueName(serviceKey); if (consumerModel != null) { rpcInvocation.put(Constants.CONSUMER_MODEL, consumerModel); rpcInvocation.put(Constants.METHOD_MODEL, consumerModel.getMethodModel(method)); } return invoker.invoke(rpcInvocation).recreate(); }
AbstractClusterInvoker.invoke()
/* org.apache.dubbo.rpc.cluster.support.AbstractClusterInvoker#invoke */ public Result invoke(final Invocation invocation) throws RpcException { //检查本地服务是否已销毁 checkWhetherDestroyed(); // 绑定attachments到invocation中,默认空,跳过 Map<String, Object> contextAttachments = RpcContext.getContext().getObjectAttachments(); if (contextAttachments != null && contextAttachments.size() != 0) { ((RpcInvocation) invocation).addObjectAttachments(contextAttachments); } //获取所有的providers List<Invoker<T>> invokers = list(invocation); //负载均衡策略 默认random LoadBalance loadbalance = initLoadBalance(invokers, invocation); RpcUtils.attachInvocationIdIfAsync(getUrl(), invocation); return doInvoke(invocation, invokers, loadbalance); }
FailoverClusterInvoker.invoke()
public Result doInvoke(Invocation invocation, final List<Invoker<T>> invokers, LoadBalance loadbalance) throws RpcException { List<Invoker<T>> copyInvokers = invokers; //检查providers不能为空 checkInvokers(copyInvokers, invocation); //获取调用的方法名 String methodName = RpcUtils.getMethodName(invocation); //调用次数 1+2次重试 int len = getUrl().getMethodParameter(methodName, RETRIES_KEY, DEFAULT_RETRIES) + 1; if (len <= 0) { len = 1; } // retry loop. RpcException le = null; // last exception. List<Invoker<T>> invoked = new ArrayList<Invoker<T>>(copyInvokers.size()); // invoked invokers. Set<String> providers = new HashSet<String>(len); for (int i = 0; i < len; i++) { //Reselect before retry to avoid a change of candidate `invokers`. //NOTE: if `invokers` changed, then `invoked` also lose accuracy. if (i > 0) { //再次检查invokers.destroyed checkWhetherDestroyed(); copyInvokers = list(invocation); // check again checkInvokers(copyInvokers, invocation); } //负载均衡策略,选取一个invoker Invoker<T> invoker = select(loadbalance, invocation, copyInvokers, invoked); //标记已经调用过的invoker,重试时,换其他invoker重试 invoked.add(invoker); RpcContext.getContext().setInvokers((List) invoked); try { Result result = invoker.invoke(invocation); if (le != null && logger.isWarnEnabled()) { logger.warn("Although retry the method " + methodName + " in the service " + getInterface().getName() + " was successful by the provider " + invoker.getUrl().getAddress() + ", but there have been failed providers " + providers + " (" + providers.size() + "/" + copyInvokers.size() + ") from the registry " + directory.getUrl().getAddress() + " on the consumer " + NetUtils.getLocalHost() + " using the dubbo version " + Version.getVersion() + ". Last error is: " + le.getMessage(), le); } return result; } catch (RpcException e) { if (e.isBiz()) { // biz exception. throw e; } le = e; } catch (Throwable e) { le = new RpcException(e.getMessage(), e); } finally { providers.add(invoker.getUrl().getAddress()); } } throw new RpcException(le.getCode(), "Failed to invoke the method " + methodName + " in the service " + getInterface().getName() + ". Tried " + len + " times of the providers " + providers + " (" + providers.size() + "/" + copyInvokers.size() + ") from the registry " + directory.getUrl().getAddress() + " on the consumer " + NetUtils.getLocalHost() + " using the dubbo version " + Version.getVersion() + ". Last error is: " + le.getMessage(), le.getCause() != null ? le.getCause() : le); }
AsyncToSyncInvoker.invoke()
public Result invoke(Invocation invocation) throws RpcException { Result asyncResult = invoker.invoke(invocation); try { if (InvokeMode.SYNC == ((RpcInvocation) invocation).getInvokeMode()) { /** * NOTICE! * must call {@link java.util.concurrent.CompletableFuture#get(long, TimeUnit)} because * {@link java.util.concurrent.CompletableFuture#get()} was proved to have serious performance drop. */ asyncResult.get(Integer.MAX_VALUE, TimeUnit.MILLISECONDS); } } catch (InterruptedException e) { throw new RpcException("Interrupted unexpectedly while waiting for remote result to return! method: " + invocation.getMethodName() + ", provider: " + getUrl() + ", cause: " + e.getMessage(), e); } catch (ExecutionException e) { Throwable t = e.getCause(); if (t instanceof TimeoutException) { throw new RpcException(RpcException.TIMEOUT_EXCEPTION, "Invoke remote method timeout. method: " + invocation.getMethodName() + ", provider: " + getUrl() + ", cause: " + e.getMessage(), e); } else if (t instanceof RemotingException) { throw new RpcException(RpcException.NETWORK_EXCEPTION, "Failed to invoke remote method: " + invocation.getMethodName() + ", provider: " + getUrl() + ", cause: " + e.getMessage(), e); } else { throw new RpcException(RpcException.UNKNOWN_EXCEPTION, "Fail to invoke remote method: " + invocation.getMethodName() + ", provider: " + getUrl() + ", cause: " + e.getMessage(), e); } } catch (Throwable e) { throw new RpcException(e.getMessage(), e); } return asyncResult; }
AbstractInvoker.invoke()
public Result invoke(Invocation inv) throws RpcException { // if invoker is destroyed due to address refresh from registry, let's allow the current invoke to proceed if (destroyed.get()) { logger.warn("Invoker for service " + this + " on consumer " + NetUtils.getLocalHost() + " is destroyed, " + ", dubbo version is " + Version.getVersion() + ", this invoker should not be used any longer"); } RpcInvocation invocation = (RpcInvocation) inv; invocation.setInvoker(this); if (CollectionUtils.isNotEmptyMap(attachment)) { invocation.addObjectAttachmentsIfAbsent(attachment); } Map<String, Object> contextAttachments = RpcContext.getContext().getObjectAttachments(); if (CollectionUtils.isNotEmptyMap(contextAttachments)) { /** * invocation.addAttachmentsIfAbsent(context){@link RpcInvocation#addAttachmentsIfAbsent(Map)}should not be used here, * because the {@link RpcContext#setAttachment(String, String)} is passed in the Filter when the call is triggered * by the built-in retry mechanism of the Dubbo. The attachment to update RpcContext will no longer work, which is * a mistake in most cases (for example, through Filter to RpcContext output traceId and spanId and other information). */ invocation.addObjectAttachments(contextAttachments); } invocation.setInvokeMode(RpcUtils.getInvokeMode(url, invocation)); RpcUtils.attachInvocationIdIfAsync(getUrl(), invocation); AsyncRpcResult asyncResult; try { asyncResult = (AsyncRpcResult) doInvoke(invocation); } catch (InvocationTargetException e) { // biz exception Throwable te = e.getTargetException(); if (te == null) { asyncResult = AsyncRpcResult.newDefaultAsyncResult(null, e, invocation); } else { if (te instanceof RpcException) { ((RpcException) te).setCode(RpcException.BIZ_EXCEPTION); } asyncResult = AsyncRpcResult.newDefaultAsyncResult(null, te, invocation); } } catch (RpcException e) { if (e.isBiz()) { asyncResult = AsyncRpcResult.newDefaultAsyncResult(null, e, invocation); } else { throw e; } } catch (Throwable e) { asyncResult = AsyncRpcResult.newDefaultAsyncResult(null, e, invocation); } RpcContext.getContext().setFuture(new FutureAdapter(asyncResult.getResponseFuture())); return asyncResult; }
DubboInvoker.doInvoke()
protected Result doInvoke(final Invocation invocation) throws Throwable { RpcInvocation inv = (RpcInvocation) invocation; final String methodName = RpcUtils.getMethodName(invocation); inv.setAttachment(PATH_KEY, getUrl().getPath()); inv.setAttachment(VERSION_KEY, version); ExchangeClient currentClient; if (clients.length == 1) { currentClient = clients[0]; } else { currentClient = clients[index.getAndIncrement() % clients.length]; } try { boolean isOneway = RpcUtils.isOneway(getUrl(), invocation); int timeout = getUrl().getMethodPositiveParameter(methodName, TIMEOUT_KEY, DEFAULT_TIMEOUT); if (isOneway) { boolean isSent = getUrl().getMethodParameter(methodName, Constants.SENT_KEY, false); currentClient.send(inv, isSent); return AsyncRpcResult.newDefaultAsyncResult(invocation); } else { ExecutorService executor = getCallbackExecutor(getUrl(), inv); //netty调用发送请求inv = RpcInvocation CompletableFuture<AppResponse> appResponseFuture = currentClient.request(inv, timeout, executor).thenApply(obj -> (AppResponse) obj); // save for 2.6.x compatibility, for example, TraceFilter in Zipkin uses com.alibaba.xxx.FutureAdapter FutureContext.getContext().setCompatibleFuture(appResponseFuture); AsyncRpcResult result = new AsyncRpcResult(appResponseFuture, inv); result.setExecutor(executor); return result; } } catch (TimeoutException e) { throw new RpcException(RpcException.TIMEOUT_EXCEPTION, "Invoke remote method timeout. method: " + invocation.getMethodName() + ", provider: " + getUrl() + ", cause: " + e.getMessage(), e); } catch (RemotingException e) { throw new RpcException(RpcException.NETWORK_EXCEPTION, "Failed to invoke remote method: " + invocation.getMethodName() + ", provider: " + getUrl() + ", cause: " + e.getMessage(), e); } }
由于netty+javassist完全陌生,流程跑了一遍,具体不清晰