Dubbo之Cluster集群容错
Dubbo版本
- Dubbo版本2.6.7
集群作用
-
Dubbo 定义了集群接口 Cluster 以及 Cluster Invoker。集群 Cluster 用途是将多个服务提供者合并为一个 Cluster Invoker,并将这个 Invoker 暴露给服务消费者。服务消费者只需通过这个 Invoker 进行远程调用即可,至于具体调用哪个服务提供者,以及调用失败后如何处理等问题,现在都交给集群模块去处理。
-
集群模块(Cluster)是服务提供者和服务消费者的中间层,为服务消费者屏蔽了服务提供者的情况,这样服务消费者就可以专心处理远程调用相关事宜。比如发请求,接受服务提供者返回的数据等。这就是集群的作用。
-
Dubbo集群层(Cluster层)的总体工作流程
- 生成Invoker对象。
- 筛选可用的服务列表。通过
Directory#list
获取所有可用的服务列表。根据不同的ClusterInvoker筛选出不同的Invoker对象,使用Router处理改服务列表,根据路由规则过滤服务列表,最终返回剩余的服务列表 - 做负载均衡。筛选可用的服务列表后,通过不同的负载均衡策略选择出一个服务,然后调用
- 做RPC调用。
集群容错方式
-
Dubbo提供的集群容错方式
- Failover Cluster : 失败自动切换重试,当服务消费方调用服务提供者失败后,会自动切换到其他服务提供者服务器进行重试,这通常用于读操作或者具有幂等的写操作。需要注意的是,重试会带来更长延迟。可以通过
retries="2"
来设置重试次数,表示额外的重试2次 - **Failfast Cluster **:快速失败,当服务消费方调用服务提供者失败后,立即报错,即只调用一次。通常,这种模式用于非幂等性的写操作。
- Failsafe Cluster : 失败安全,当服务消费者调用服务出现异常时,直接忽略异常。这种模式一般用于写入日志等操作,即不关心失败
- Failback Cluster: 失败自动恢复,当服务消费端调用服务出现异常后,在后台记录失败的请求,并按照一定的策略后期再进行重试。这种模式通常用于消息通知操作
- Forking Cluster:并行调用多个服务提供者。当消费方调用一个接口方法后,消费者会并行调用多个服务提供者的服务,只要其中有一个成功即返回。这种模式通常用于实时性要求较高的读操作,但需要浪费更多服务资源。可通过
forks="4"
来设置最大并行数 - Broadcast Cluster:广播调用,当消费者调用一个接口方法后,Dubbo消费者会逐个调用所有服务提供者,任意一台服务器调用异常则这次调用就标志失败。这种模式通常用于通知所有提供者更新缓存或日志等本地资源信息。由于是广播,所以不需要做负载均衡
- Available Cluster:选择一个可以使用的服务提供者进行调用
- Mergeable Cluster:依次调用所有invokers, 并通过使用一个merger进行结果合并处理以返回结果。
- Failover Cluster : 失败自动切换重试,当服务消费方调用服务提供者失败后,会自动切换到其他服务提供者服务器进行重试,这通常用于读操作或者具有幂等的写操作。需要注意的是,重试会带来更长延迟。可以通过
自定义集群容错策略
-
除了以上默认提供的容错方式,如果有定制化需求,可以根据Dubbo提供的扩展接口Cluster进行定制
-
实现
Cluster
接口package com.alibaba.dubbo.spi; import com.alibaba.dubbo.rpc.Invoker; import com.alibaba.dubbo.rpc.RpcException; import com.alibaba.dubbo.rpc.cluster.Cluster; import com.alibaba.dubbo.rpc.cluster.Directory; public class LogCluster implements Cluster { @Override public <T> Invoker<T> join(Directory<T> directory) throws RpcException { return new LogClusterInvoker<>(directory); } }
-
创建
LogClusterInvoker
public class LogClusterInvoker<T> extends AbstractClusterInvoker<T> { private static final Logger logger = LoggerFactory.getLogger(LogClusterInvoker.class); public LogClusterInvoker(Directory<T> directory) { super(directory); } @Override protected Result doInvoke(Invocation invocation, List<Invoker<T>> invokers, LoadBalance loadbalance) throws RpcException { checkInvokers(invokers, invocation); //使用负载均衡策略选择一个服务提供者 Invoker<T> invoker = select(loadbalance, invocation, invokers, null); logger.info(String.format("methodName:%s,url:%s,attachments:%s", invocation.getMethodName(), invoker.getUrl(), invocation.getAttachments())); try { //执行远程调用 Result result = invoker.invoke(invocation); logger.info(String.format("result:%s,attachments:%s", result.getValue(), result.getAttachments())); return result; } catch (Throwable e) { if (e instanceof RpcException && ((RpcException) e).isBiz()) { throw (RpcException) e; } throw new RpcException(e); } } }
-
在
src/main/resources/META-INF/dubbo
目录下创建com.alibaba.dubbo.rpc.cluster.Cluster
文件,内容如下log=com.alibaba.dubbo.spi.LogCluster
-
在Consumer端配置
<dubbo:reference id="demoService" check="false" interface="com.alibaba.dubbo.demo.DemoService" cluster="log"/>
集群配置
-
集群模式配置
<dubbo:service cluster="failsafe" /> <dubbo:reference cluster="failsafe" />
重试次数
-
Dubbo 服务在尝试调用一次之后,如出现非业务异常(服务突然不可用、超时等),Dubbo 默认(Failover Cluster策略)会进行额外的最多2次重试(即总共最多3次调用)。重试次数的源码分析在下面的FailoverClusterInvoker源码分析处
-
重试次数支持两种自定义配置:
- 通过注解/xml进行固定配置
- 通过上下文进行运行时动态配置
-
通过注解/xml进行固定配置
<dubbo:service retries="2" /> <dubbo:consumer retries="2" /> <dubbo:reference retries="2" /> <dubbo:reference> <dubbo:method name="findFoo" retries="2" /> </dubbo:reference>
-
通过RpcContext进行运行时动态配置,优先级高于注解/xml进行的固定配置(两者都配置的情况下,以RpcContext配置为准).
// dubbo服务调用前,通过RpcContext动态设置本次调用的重试次数 RpcContext rpcContext = RpcContext.getContext(); rpcContext.setAttachment("retries", 5);
-
如果指定的是一个负数或者0,则设置为1
//源码部分,默认重试次数是2 Constants#DEFAULT_RETRIES=2 //如果指定的是一个负数或者0,则设置为1 int len = getUrl().getMethodParameter(invocation.getMethodName(), Constants.RETRIES_KEY, Constants.DEFAULT_RETRIES) + 1; if (len <= 0) { len = 1; }
Cluster源码分析
- Cluster 是接口,而 Cluster Invoker 是一种 Invoker。服务提供者的选择逻辑,以及远程调用失败后的的处理逻辑均是封装在 Cluster Invoker 中。 Cluster 接口仅用于生成 Cluster Invoker
-
以
FailoverCluster
为例public class FailoverCluster implements Cluster { public final static String NAME = "failover"; @Override public <T> Invoker<T> join(Directory<T> directory) throws RpcException { return new FailoverClusterInvoker<T>(directory); } }
ClusterInvoker源码分析
-
集群工作过程可分为两个阶段,第一个阶段是在服务消费者初始化期间。第二个阶段是在服务消费者进行远程调用时,此时 AbstractClusterInvoker 的 invoke 方法会被调用
-
AbstractClusterInvoker#invoke
:主要用于获取所有的 Invoker,以及加载 LoadBalance。最后再调用模板方法 doInvoke 进行后续操作@Override public Result invoke(final Invocation invocation) throws RpcException { checkWhetherDestroyed(); LoadBalance loadbalance = null; // binding attachments into invocation. // 绑定 attachments 到 invocation 中. Map<String, String> contextAttachments = RpcContext.getContext().getAttachments(); if (contextAttachments != null && contextAttachments.size() != 0) { ((RpcInvocation) invocation).addAttachments(contextAttachments); } //从RegistryDirectory管理的RouterChain的route()方法中获取保存的invoker列表 List<Invoker<T>> invokers = list(invocation); if (invokers != null && !invokers.isEmpty()) { loadbalance = ExtensionLoader.getExtensionLoader(LoadBalance.class).getExtension(invokers.get(0).getUrl() .getMethodParameter(RpcUtils.getMethodName(invocation), Constants.LOADBALANCE_KEY, Constants.DEFAULT_LOADBALANCE)); } RpcUtils.attachInvocationIdIfAsync(getUrl(), invocation); //子类实现具体的逻辑 return doInvoke(invocation, invokers, loadbalance); }
FailsafeClusterInvoker
-
当服务消费者调用服务出现异常时,直接忽略异常
@Override public Result doInvoke(Invocation invocation, List<Invoker<T>> invokers, LoadBalance loadbalance) throws RpcException { try { checkInvokers(invokers, invocation); Invoker<T> invoker = select(loadbalance, invocation, invokers, null); return invoker.invoke(invocation); } catch (Throwable e) { //直接忽略异常,返回一个空结果 logger.error("Failsafe ignore exception: " + e.getMessage(), e); return new RpcResult(); // ignore } }
FailoverClusterInvoker
-
失败自动切换重试,当服务消费方调用服务提供者失败后,会自动切换到其他服务提供者服务器进行重试
- 检查通过负载均衡策略获取的服务者是否可用
- 获取重试次数,默认是2次。如果是负数或者0,则设置为1
- 如果第一次调用成功,则直接返回结果
- 如果第一次调用失败,则重试,此时需要重新获取服务列表(可能发生了变化)
@Override @SuppressWarnings({"unchecked", "rawtypes"}) public Result doInvoke(Invocation invocation, final List<Invoker<T>> invokers, LoadBalance loadbalance) throws RpcException { //所有的服务提供者 List<Invoker<T>> copyinvokers = invokers; checkInvokers(copyinvokers, invocation); //获取重试次数,默认值是2 int len = getUrl().getMethodParameter(invocation.getMethodName(), Constants.RETRIES_KEY, Constants.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) { //检查实例是否销毁(是否有其他线程调用消费者的销毁) checkWhetherDestroyed(); //重新获取所有的服务提供者 copyinvokers = list(invocation); // check again 再次检查服务提供者是否为空 checkInvokers(copyinvokers, invocation); } //选择负载均衡策略 Invoker<T> invoker = select(loadbalance, invocation, copyinvokers, invoked); 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 " + invocation.getMethodName() + " 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 != null ? le.getCode() : 0, "Failed to invoke the method " + invocation.getMethodName() + " 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 != null ? le.getMessage() : ""), le != null && le.getCause() != null ? le.getCause() : le); }
FailbackClusterInvoker
-
失败自动恢复,当服务消费端调用服务出现异常后,在后台记录失败的请求,并按照一定的策略后期再进行重试
- 检查服务列表invokers是否为空
- 根据负载均衡策略选择一个invoker
- 远程调用,如果失败,则把当前上下文添加到定时器中.并返回一个空的结果
@Override protected Result doInvoke(Invocation invocation, List<Invoker<T>> invokers, LoadBalance loadbalance) throws RpcException { try { //检查invokers是否合法,及是否为空 checkInvokers(invokers, invocation); //根据负载均衡策略选择一个invoker Invoker<T> invoker = select(loadbalance, invocation, invokers, null); //远程调用 return invoker.invoke(invocation); } catch (Throwable e) { logger.error("Failback to invoke method " + invocation.getMethodName() + ", wait for retry in background. Ignored exception: " + e.getMessage() + ", ", e); //如果失败则添加到定时器中 addFailed(invocation, this); return new RpcResult(); // ignore } }
-
添加到定时器的方法
addFailed
private void addFailed(Invocation invocation, AbstractClusterInvoker<?> router) { if (retryFuture == null) { synchronized (this) { if (retryFuture == null) { // 创建定时任务,每隔5秒执行一次 retryFuture = scheduledExecutorService.scheduleWithFixedDelay(new Runnable() { @Override public void run() { // collect retry statistics try { //重试任务 retryFailed(); } catch (Throwable t) { // Defensive fault tolerance logger.error("Unexpected error occur at collect statistic", t); } } }, RETRY_FAILED_PERIOD, RETRY_FAILED_PERIOD, TimeUnit.MILLISECONDS); } } } failed.put(invocation, router); }
-
重试任务retryFailed方法
void retryFailed() { if (failed.size() == 0) { return; } // 遍历 failed,对失败的调用进行重试 for (Map.Entry<Invocation, AbstractClusterInvoker<?>> entry : new HashMap<Invocation, AbstractClusterInvoker<?>>( failed).entrySet()) { Invocation invocation = entry.getKey(); Invoker<?> invoker = entry.getValue(); try { //再次发起远程调用 invoker.invoke(invocation); //调用成功后,从 failed 中移除 invoker failed.remove(invocation); } catch (Throwable e) { //只打印异常,不做其他处理,等待下次定时调用 logger.error("Failed retry to invoke method " + invocation.getMethodName() + ", waiting again.", e); } } }
ForkingClusterInvoker
-
并行调用多个服务提供者。当消费方调用一个接口方法后,消费者会并行调用多个服务提供者的服务,只要其中有一个成功即返回
- 获取
fork=xx
配置,默认是2。如果fork配置超出边界,则以服务列表数量为准,否则,遍历fork数量,选择fork数量的列表 - 遍历选择的服务列表,使用线程池进行并行调用,并将成功结果存储到阻塞队列中。如果所有结果都发生异常,则会将最后一个异常存储到阻塞队列中
- 这里需要注意的是,即使
ref.poll
返回了结果,其他线程还是会继续执行(继续远程调用)
public Result doInvoke(final Invocation invocation, List<Invoker<T>> invokers, LoadBalance loadbalance) throws RpcException { try { checkInvokers(invokers, invocation); final List<Invoker<T>> selected; //获取forks配置参数,默认是2 final int forks = getUrl().getParameter(Constants.FORKS_KEY, Constants.DEFAULT_FORKS); //获取超时配置 final int timeout = getUrl().getParameter(Constants.TIMEOUT_KEY, Constants.DEFAULT_TIMEOUT); // 如果 forks 配置无效,则直接将 invokers 赋值给 selected if (forks <= 0 || forks >= invokers.size()) { selected = invokers; } else { selected = new ArrayList<Invoker<T>>(); // 循环选出 forks 个 Invoker,并添加到 selected 中 for (int i = 0; i < forks; i++) { // TODO. Add some comment here, refer chinese version for more details. Invoker<T> invoker = select(loadbalance, invocation, invokers, selected); if (!selected.contains(invoker)) {//Avoid add the same invoker several times. selected.add(invoker); } } } RpcContext.getContext().setInvokers((List) selected); final AtomicInteger count = new AtomicInteger(); final BlockingQueue<Object> ref = new LinkedBlockingQueue<Object>(); // 遍历 selected 列表 for (final Invoker<T> invoker : selected) { // 为每个 Invoker 创建一个执行线程,这是一个后台线程 executor.execute(new Runnable() { @Override public void run() { try { // 进行远程调用 Result result = invoker.invoke(invocation); // 将结果存到阻塞队列中 ref.offer(result); } catch (Throwable e) { int value = count.incrementAndGet(); //仅在 value 大于等于 selected.size() 时,才将异常对象 //可以保证异常对象不会出现在正常结果的前面,这样可从阻塞队列中优先取出正常的结果。 //如果所有的都发生异常,就只有一个异常会存在队列里,只要有一个成功,队列里就会有一个正确的结果 if (value >= selected.size()) { // 将异常对象存入到阻塞队列中 ref.offer(e); } } } }); } try { // 从阻塞队列中取出远程调用结果 Object ret = ref.poll(timeout, TimeUnit.MILLISECONDS); // 如果结果类型为 Throwable,则抛出异常。否则返回结果 if (ret instanceof Throwable) { Throwable e = (Throwable) ret; throw new RpcException(e instanceof RpcException ? ((RpcException) e).getCode() : 0, "Failed to forking invoke provider " + selected + ", but no luck to perform the invocation. Last error is: " + e.getMessage(), e.getCause() != null ? e.getCause() : e); } return (Result) ret; } catch (InterruptedException e) { throw new RpcException("Failed to forking invoke provider " + selected + ", but no luck to perform the invocation. Last error is: " + e.getMessage(), e); } } finally { // clear attachments which is binding to current thread. RpcContext.getContext().clearAttachments(); } }
- 获取
BroadcastClusterInvoker
-
BroadcastCluster:广播调用,当消费者调用一个接口方法后,Dubbo消费者会逐个调用所有服务提供者,任意一台服务器调用异常则这次调用就标志失败,只有最后一个异常回被抛出
public Result doInvoke(final Invocation invocation, List<Invoker<T>> invokers, LoadBalance loadbalance) throws RpcException { checkInvokers(invokers, invocation); RpcContext.getContext().setInvokers((List) invokers); RpcException exception = null; Result result = null; //循环调用所有的服务列表,如果其中有一个出现异常,则抛出异常 //如果没有出现异常,则返回最后一个服务提供者的返回结果 for (Invoker<T> invoker : invokers) { try { result = invoker.invoke(invocation); } catch (RpcException e) { exception = e; logger.warn(e.getMessage(), e); } catch (Throwable e) { exception = new RpcException(e.getMessage(), e); logger.warn(e.getMessage(), e); } } if (exception != null) { throw exception; } return result; }
AvailableClusterInvoker
-
AvailableClusterInvoker:选择一个可以使用的Invoke调用
public class AvailableClusterInvoker<T> extends AbstractClusterInvoker<T> { public AvailableClusterInvoker(Directory<T> directory) { super(directory); } @Override public Result doInvoke(Invocation invocation, List<Invoker<T>> invokers, LoadBalance loadbalance) throws RpcException { //选择一个可使用的进行调用 for (Invoker<T> invoker : invokers) { if (invoker.isAvailable()) { return invoker.invoke(invocation); } } throw new RpcException("No provider available in " + invokers); } }
MergeableClusterInvoker
-
MergeableClusterInvoker
容错,依次调用所有invokers, 并通过使用一个merger进行结果合并处理以返回结果。1. 搜搜所有分组,根据返回结果的类型自动查找合并器。该接口中getMenuItems方法不做合并 <dubbo:reference id="demoService" group="*" merger="true" interface="com.alibaba.dubbo.demo.DemoService"> <dubbo:method name="getMenuItems" meger="false"/> </dubbo:reference> 2. 指定方法合并结果 <dubbo:reference id="demoService" group="*" interface="com.alibaba.dubbo.demo.DemoService"> <dubbo:method name="getMenuItems" meger="mymerge"/> </dubbo:reference> 3. 调用返回结果的指定方法进行合并 <dubbo:reference id="demoService" group="*" interface="com.alibaba.dubbo.demo.DemoService"> <dubbo:method name="getMenuItems" meger=".addAll"/> </dubbo:reference>
-
当一个接口有多种实现,消费者又需要同时引用不同的实现时,可以用group 来区分不同的实现。如果我们需要并行调用不同group 的服务,并且要把结果集合并起来,则需要用到Merger特性。Merger实现了多个服务调用后结果合并的逻辑。虽然业务层可以自行实现这个能力,但Dubbo直接封装到框架中,作为一种扩展点能力,简化了业务开发的复杂度
-
MergeableClusterInvoker
并没有继承AbstractClusterInvoker
,而是直接实现了Invoker
接口- 获取所有的Invoker服务列表
- 判断方法是否有合并器,如果没有,则不会并行调用多个group,找到第一个可以调用的Invoker直接调用就返回了。如果有合井器则继续执行
- 获取接口的返回类型。通过反射获得返回类型,后续要根据这个返回值查找不同的合并器
- 使用线程异步调用所有的服务列表,阻塞获取结果,将没有异常的结果放到结果列表中
- 如果结果列表为空,则直接返回一个空结果。如果只有一个结果,则直接返回。如果返回值是void,也直接返回
- 合并结果集。如果配置的是
merger=".addAll"
,则直接通过反射调用返回类型中的addAll方法合并结果集。例如:返回类型是Set,则调用Set.addAll来合并结果 - 合并有两种方式,根据配置不同可用分为基于方法的合并和基于merger的合并。
@Override @SuppressWarnings("rawtypes") public Result invoke(final Invocation invocation) throws RpcException { //获取所有的服务列表 List<Invoker<T>> invokers = directory.list(invocation); //获取merger配置 String merger = getUrl().getMethodParameter(invocation.getMethodName(), Constants.MERGER_KEY); //如果没有指定merger配置,则选择一个可以利用的服务提供者进行调用(相当于AvailableClusterInvoker) if (ConfigUtils.isEmpty(merger)) { // If a method doesn't have a merger, only invoke one Group for (final Invoker<T> invoker : invokers) { if (invoker.isAvailable()) { return invoker.invoke(invocation); } } //如果没有可利用的Invoker,则尝试使用第一个。这里应该加判断第一个是否有? return invokers.iterator().next().invoke(invocation); } //方法的返回类型 Class<?> returnType; try { returnType = getInterface().getMethod( invocation.getMethodName(), invocation.getParameterTypes()).getReturnType(); } catch (NoSuchMethodException e) { returnType = null; } Map<String, Future<Result>> results = new HashMap<String, Future<Result>>(); //异步调用所有的invoke for (final Invoker<T> invoker : invokers) { Future<Result> future = executor.submit(new Callable<Result>() { @Override public Result call() throws Exception { return invoker.invoke(new RpcInvocation(invocation, invoker)); } }); results.put(invoker.getUrl().getServiceKey(), future); } Object result = null; List<Result> resultList = new ArrayList<Result>(results.size()); int timeout = getUrl().getMethodParameter(invocation.getMethodName(), Constants.TIMEOUT_KEY, Constants.DEFAULT_TIMEOUT); for (Map.Entry<String, Future<Result>> entry : results.entrySet()) { Future<Result> future = entry.getValue(); try { Result r = future.get(timeout, TimeUnit.MILLISECONDS); //如果有异常则打印日志,没有异常则放到结果列表resultList中 if (r.hasException()) { log.error("Invoke " + getGroupDescFromServiceKey(entry.getKey()) + " failed: " + r.getException().getMessage(), r.getException()); } else { resultList.add(r); } } catch (Exception e) { throw new RpcException("Failed to invoke service " + entry.getKey() + ": " + e.getMessage(), e); } } //如果结果列表为空,则返回一个空结果 if (resultList.isEmpty()) { return new RpcResult((Object) null); } else if (resultList.size() == 1) { //如果只有一个结果,则直接返回 return resultList.iterator().next(); } if (returnType == void.class) { return new RpcResult((Object) null); } //根据方法来合并,将调用返回结果的指定方法进行合并 //如果配置的是`merger=".addAll"`,则直接通过反射调用返回类型中的addAll方法合并结果集。 //例如:返回类型是Set,则调用Set.addAll来合并结果 if (merger.startsWith(".")) { //截取字符串,获取调用的方法名 merger = merger.substring(1); Method method; try { //获取方法对象 method = returnType.getMethod(merger, returnType); } catch (NoSuchMethodException e) { throw new RpcException("Can not merge result because missing method [ " + merger + " ] in class [ " + returnType.getClass().getName() + " ]"); } //非public方法设置暴力访问 if (!Modifier.isPublic(method.getModifiers())) { method.setAccessible(true); } result = resultList.remove(0).getValue(); try { if (method.getReturnType() != void.class && method.getReturnType().isAssignableFrom(result.getClass())) { // 方法返回类型匹配(不是void,而且与方法返回相同的类型),合并时,修改 result for (Result r : resultList) { result = method.invoke(result, r.getValue()); } } else { // 方法返回类型不匹配,合并时,不修改 result for (Result r : resultList) { method.invoke(result, r.getValue()); } } } catch (Exception e) { throw new RpcException("Can not merge result: " + e.getMessage(), e); } } else { Merger resultMerger; //如果是默认的Merger(参数为true或default),则用MergerFactory获取默认的合并器 //否则通过扩展加载器ExtensionLoader获取对应名称的合并器 if (ConfigUtils.isDefault(merger)) { resultMerger = MergerFactory.getMerger(returnType); } else { resultMerger = ExtensionLoader.getExtensionLoader(Merger.class).getExtension(merger); } //如果找到合并器则合并,否则抛出异常 if (resultMerger != null) { List<Object> rets = new ArrayList<Object>(resultList.size()); for (Result r : resultList) { rets.add(r.getValue()); } result = resultMerger.merge( rets.toArray((Object[]) Array.newInstance(returnType, 0))); } else { throw new RpcException("There is no merger to merge result."); } } return new RpcResult(result); }