dubbo 异步回调

Posted 偶尔发呆

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了dubbo 异步回调相关的知识,希望对你有一定的参考价值。

dubbo 异步回调的使用

业务接口:

public interface HelloService {
    String sayHello();
    void sayHi(String name);
}

回调服务类:

public class CbService {
    // onreturn 函数的参数是有限定的,细节下面提及。
    public void onreturn(String str) {
        System.out.println("onreturn:" + str);
    }
    public void onthrow(Throwable ex) {
        System.out.println("onthrow");
    }
    public String oninvoke() {
        System.out.println("oninvoke");
        return null;
    }
}

xml 配置:(oninvoke 暂时没有配置好)

<bean id="cbService" class="com.zhang.CbService"></bean>
<dubbo:reference id="hello"
    loadbalance="roundrobin" check="false" interface="com.zhang.HelloService" >
    <dubbo:method name="sayHello"
        async="true"
        onreturn="cbService.onreturn"
        onthrow="cbService.onthrow">
    </dubbo:method>
</dubbo:reference>


1. 异步回调的源头从 FutureFilter 发起,这是一个 consumer 端的 filter,它为 Future 设置回调函数。

@Activate(group = Constants.CONSUMER)
public class FutureFilter implements Filter {

    public Result invoke(final Invoker<?> invoker, final Invocation invocation) throws RpcException {
        final boolean isAsync = RpcUtils.isAsync(invoker.getUrl(), invocation);
        
        fireInvokeCallback(invoker, invocation);
        // 发起调用请求
        Result result = invoker.invoke(invocation);
        
        if (isAsync) {
            // 注册异步回调函数
            asyncCallback(invoker, invocation);
        } else {
            syncCallback(invoker, invocation, result);
        }
        return result;
    }
    
    // 为 Future 设置 callback
    private void asyncCallback(final Invoker<?> invoker, final Invocation invocation) {
        Future<?> f = RpcContext.getContext().getFuture();
        if (f instanceof FutureAdapter) {
            ResponseFuture future = ((FutureAdapter<?>)f).getFuture();
            future.setCallback(new ResponseCallback() {
                public void done(Object rpcResult) {
                    if (rpcResult == null){
                        logger.error(new IllegalStateException("invalid result value : null, expected "+Result.class.getName()));
                        return;
                    }
                    ///must be rpcResult
                    if (! (rpcResult instanceof Result)){
                        logger.error(new IllegalStateException("invalid result type :" + rpcResult.getClass() + ", expected "+Result.class.getName()));
                        return;
                    }
                    Result result = (Result) rpcResult;
                    if (result.hasException()) {
                        fireThrowCallback(invoker, invocation, result.getException());
                    } else {
                        fireReturnCallback(invoker, invocation, result.getValue());
                    }
                }
                public void caught(Throwable exception) {
                    fireThrowCallback(invoker, invocation, exception);
                }
            });
        }
    }
    
    private void fireReturnCallback(final Invoker<?> invoker, final Invocation invocation, final Object result) {
        final Method onReturnMethod = (Method)StaticContext.getSystemContext().get(StaticContext.getKey(invoker.getUrl(), invocation.getMethodName(), Constants.ON_RETURN_METHOD_KEY));
        final Object onReturnInst = StaticContext.getSystemContext().get(StaticContext.getKey(invoker.getUrl(), invocation.getMethodName(), Constants.ON_RETURN_INSTANCE_KEY));

        //not set onreturn callback
        if (onReturnMethod == null  &&  onReturnInst == null ){
            return ;
        }
        
        if (onReturnMethod == null  ||  onReturnInst == null ){
            throw new IllegalStateException("service:" + invoker.getUrl().getServiceKey() +" has a onreturn callback config , but no such "+(onReturnMethod == null ? "method" : "instance")+" found. url:"+invoker.getUrl());
        }
        if (onReturnMethod != null && ! onReturnMethod.isAccessible()) {
            onReturnMethod.setAccessible(true);
        }
        
        Object[] args = invocation.getArguments();
        Object[] params ;
        Class<?>[] rParaTypes = onReturnMethod.getParameterTypes() ;
        if (rParaTypes.length >1 ) {
            if (rParaTypes.length == 2 && rParaTypes[1].isAssignableFrom(Object[].class)){
                params = new Object[2];
                params[0] = result;
                params[1] = args ;
            }else {
                params = new Object[args.length + 1];
                params[0] = result;
                System.arraycopy(args, 0, params, 1, args.length);
            }
        } else {
            params = new Object[] { result };
        }
        // 经过前面的 if else 后,必定有 params[0] = result;
        // result 是 RpcResult 的 value,即 provider 接口的返回值。
        // 所以,CbService 的 onreturn 函数的第一个参数必须是接口的返回值。
        try {
            onReturnMethod.invoke(onReturnInst, params);
        } catch (InvocationTargetException e) {
            fireThrowCallback(invoker, invocation, e.getTargetException());
        } catch (Throwable e) {
            fireThrowCallback(invoker, invocation, e);
        }
    }
}


2. 当 consumer 收到服务端的响应时,触发回调函数,调用栈如下:

 

以上是关于dubbo 异步回调的主要内容,如果未能解决你的问题,请参考以下文章

如何简单粗暴的搞定dubbo调用模块

NodeJs异步的执行过程

dubbo实现动态调用

看一下“Dubbo 2.7”的三大新特性

RPC理论以及Dubbo的使用介绍

jQuery-异步请求