简介
该集群容错模式下,可以合并结果集,一般和 group 一起使用,具体使用规则参考 分组聚合
实现逻辑
如果没有配置 merger,则不合并结果集,直接调用实例执行后返回
异步调用所有的实例
获取要调用的方法的返回类型,根据返回类型进行调用,如果是 . 开头的,则调用方法;否则如果有配置自定义合并器,则调用自动以合并器,如果没有则调用默认的合并器
源代码
public class MergeableClusterInvoker<T> implements Invoker<T> {
private static final Logger log = LoggerFactory.getLogger(MergeableClusterInvoker.class);
private final Directory<T> directory;
private ExecutorService executor = Executors.newCachedThreadPool(new NamedThreadFactory("mergeable-cluster-executor", true));
public MergeableClusterInvoker(Directory<T> directory) {
this.directory = directory;
}
@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);
if (ConfigUtils.isEmpty(merger)) { // If a method doesn't have a merger, only invoke one Group
// 没有配置 merger,则默认所有调用实例都是一个组的
for (final Invoker<T> invoker : invokers) {
if (invoker.isAvailable()) {
// 调用可用的实例
return invoker.invoke(invocation);
}
}
// 如果都是不可用的,则调用第一个实例
return invokers.iterator().next().invoke(invocation);
}
Class<?> returnType;
try {
returnType = getInterface().getMethod(
invocation.getMethodName(), invocation.getParameterTypes()).getReturnType();
} catch (NoSuchMethodException e) {
returnType = null;
}
// 异步调用所有的实例,并把对象存储到 results 中
Map<String, Future<Result>> results = new HashMap<String, Future<Result>>();
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);
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);
}
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() + " ]");
}
if (!Modifier.isPublic(method.getModifiers())) {
method.setAccessible(true);
}
result = resultList.remove(0).getValue();
try {
// 调用方法进行合并
if (method.getReturnType() != void.class
&& method.getReturnType().isAssignableFrom(result.getClass())) {
for (Result r : resultList) {
result = method.invoke(result, r.getValue());
}
} else {
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;
if (ConfigUtils.isDefault(merger)) {
// 执行默认的合并器
resultMerger = MergerFactory.getMerger(returnType);
} else {
// 执行自定义的 Merger 合并器来合并
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());
}
// 调用合并器 merge 方法
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);
}
@Override
public Class<T> getInterface() {
return directory.getInterface();
}
@Override
public URL getUrl() {
return directory.getUrl();
}
@Override
public boolean isAvailable() {
return directory.isAvailable();
}
@Override
public void destroy() {
directory.destroy();
}
private String getGroupDescFromServiceKey(String key) {
int index = key.indexOf("/");
if (index > 0) {
return "group [ " + key.substring(0, index) + " ]";
}
return key;
}
}