(十七)分组聚合

来源:互联网 发布:gta5淘宝封禁 编辑:程序博客网 时间:2024/05/29 17:41
一般来说,消费者进行远程调用时,会调用远程的一个提供者。
现在可以消费者调用一个方法,可以调用提供者多个方法再聚合结果返回。
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

..

原创粉丝点击