(十七)分组聚合
来源:互联网 发布:gta5淘宝封禁 编辑:程序博客网 时间:2024/05/29 17:41
一般来说,消费者进行远程调用时,会调用远程的一个提供者。
现在可以消费者调用一个方法,可以调用提供者多个方法再聚合结果返回。
看看合并集群MergeableCluster是怎么调用分组的:
MergeableCluster用多线程分别调用多个分组里的提供者,即源码“M2处”,并将分组的返回结果聚合起来“M3处”,在“M4处”,如果没有配置聚合器,则使用dubbo默认的聚合器,否则,“M5处”,会使用用户配置的聚合器合并结果返回,自己定义的聚合器,实现Merger接口即可。
现在可以消费者调用一个方法,可以调用提供者多个方法再聚合结果返回。
public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException { url = url.setProtocol(url.getParameter(Constants.REGISTRY_KEY, Constants.DEFAULT_REGISTRY)).removeParameter(Constants.REGISTRY_KEY); Registry registry = registryFactory.getRegistry(url); if (RegistryService.class.equals(type)) { return proxyFactory.getInvoker((T) registry, type, url); } // group="a,b" or group="*" Map<String, String> qs = StringUtils.parseQueryString(url.getParameterAndDecoded(Constants.REFER_KEY)); String group = qs.get(Constants.GROUP_KEY); //C1处 if (group != null && group.length() > 0 ) { if ( ( Constants.COMMA_SPLIT_PATTERN.split( group ) ).length > 1 || "*".equals( group ) ) { return doRefer( getMergeableCluster(), registry, type, url ); } } return doRefer(cluster, registry, type, url);}Consumer端在初始化reference时,先判断是否有配置group属性,如果有配置,则使用合并集群,即“C1处”,多个分组用“,”分隔。
看看合并集群MergeableCluster是怎么调用分组的:
public Result invoke(final Invocation invocation) throws RpcException { List<Invoker<T>> invokers = directory.list(invocation); String merger = getUrl().getMethodParameter( invocation.getMethodName(), Constants.MERGER_KEY ); //M1处 if ( ConfigUtils.isEmpty(merger) ) { // 如果方法不需要Merge,退化为只调一个Group 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; } //M2处 Map<String, Future<Result>> results = new HashMap<String, Future<Result>>(); for( final Invoker<T> invoker : invokers ) { Future<Result> future = executor.submit( new Callable<Result>() { 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 ); //M3处 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(new StringBuilder(32).append("Invoke ") .append(getGroupDescFromServiceKey(entry.getKey())) .append(" failed: ") .append(r.getException().getMessage()).toString(), r.getException()); } else { resultList.add(r); } } catch ( Exception e ) { throw new RpcException( new StringBuilder( 32 ) .append( "Failed to invoke service " ) .append( entry.getKey() ) .append( ": " ) .append( e.getMessage() ).toString(), e ); } } if (resultList.size() == 0) { 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( new StringBuilder( 32 ) .append( "Can not merge result because missing method [ " ) .append( merger ) .append( " ] in class [ " ) .append( returnType.getClass().getName() ) .append( " ]" ) .toString() ); } if ( method != null ) { 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( new StringBuilder( 32 ) .append( "Can not merge result: " ) .append( e.getMessage() ).toString(), e ); } } else { throw new RpcException( new StringBuilder( 32 ) .append( "Can not merge result because missing method [ " ) .append( merger ) .append( " ] in class [ " ) .append( returnType.getClass().getName() ) .append( " ]" ) .toString() ); } } else { //M4处 Merger resultMerger; 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()); } //M5处 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 ); }虽然reference引用标签配置了group属性,但如果调用的方法配置不使用group属性,则也会退化为只调用一个提供者的,即源码“M1处”;
MergeableCluster用多线程分别调用多个分组里的提供者,即源码“M2处”,并将分组的返回结果聚合起来“M3处”,在“M4处”,如果没有配置聚合器,则使用dubbo默认的聚合器,否则,“M5处”,会使用用户配置的聚合器合并结果返回,自己定义的聚合器,实现Merger接口即可。
package com.alibaba.dubbo.rpc.cluster;public interface Merger<T> { T merge(T... items);}并在META-INF/dubbo/internal目录下配置com.alibaba.dubbo.rpc.cluster.Merger自己的聚合器,配置跟dubbo的过滤器类似,比如:
#com.alibaba.dubbo.rpc.cluster.Merger分组聚合结果扩展myMerger = xx.xx.MyMerger
..
阅读全文
0 0
- (十七)分组聚合
- ThinkPHP使用分组详细介绍(十七)
- 数据库(5)聚合、分组、排序、分页
- 组函数(聚合函数),分组函数
- 聚合分析与分组
- 聚合函数与分组
- 聚合分析和分组
- 聚合和分组
- Mongodb 聚合 分组
- 分组和聚合函数
- sql分组聚合练习
- dubbo 分组聚合
- 聚合函数与分组
- 聚合函数与分组
- 聚合函数与分组
- 聚合函数与分组
- 聚合函数与分组
- mysql 分组聚合事例
- JQuery 加载就绪(ready)
- Python使用ElementTree处理XML
- Android系统权限和root权限
- LeetCode-Missing Number
- linux快捷键
- (十七)分组聚合
- 怎样选择机器学习方法(6)
- 前端下载的实现
- 一个“老”程序员在阿里、百度、58赶集、美团等公司面试经验总结
- MySql的内连、左连、右连 用法及区别
- 关于安装在VirtualBox中ubuntu共享文件夹的问题
- JavaLombok
- python pandas (ix & iloc &loc) 的区别
- 生成当前日期开头加0001,0002,0003......的方法