• Dubbo事件回调


    方法说明
    • oninvoke方法:必须具有与真实的被调用方法sayHello相同的入参列表:例如,oninvoke(String name)
    • onreturn方法:至少要有一个入参且第一个入参必须与sayHello的返回类型相同,接收返回结果:例如,onreturnWithoutParam(String result),可以有多个参数,多个参数的情况下,第一个后边的所有参数都是用来接收sayHello入参的:例如, onreturn(String result, String name)
    • onthrow方法:至少要有一个入参且第一个入参类型为Throwable或其子类,接收返回结果;例如,onthrow(Throwable ex),可以有多个参数,多个参数的情况下,第一个后边的所有参数都是用来接收sayHello入参的:例如,onthrow(Throwable ex, String name)
    • 如果是consumer在调用provider的过程中,出现异常时不会走onthrow方法的,onthrow方法只会在provider返回的RpcResult中含有Exception对象时,才会执行。(dubbo中下层服务的Exception会被放在响应RpcResult的exception对象中传递给上层服务)
     
     
    一、使用示例
     
    服务消费者端
    public interface Notify {
        void onreturnNoParam(String result); // 调用之后,没有参数的
        void onreturn(String result, String name); // 调用之后
        void onthrow(Throwable ex, String name); // 出现异常
    }
    
    public class NotifyService implements Notify {
    
        @Override
        public void onreturnNoParam(String result) {
            System.out.println("======onreturnNoParam======, result: " + result);
        }
    
        @Override
        public void onreturn(String result, String name) {
            System.out.println("======onreturn======, param: " + name + ", result: " + result);
        }
    
        @Override
        public void onthrow(Throwable ex, String name) {
            System.out.println("======onthrow======, param: " + name + ", exception: " + ex.getMessage());
        }
    }
    <bean id="notifyService"  class="com.notify.NotifyService"/>
    <dubbo:reference id="demoService" check="false" interface="com.alibaba.dubbo.demo.DemoService">
        <dubbo:method name="sayHello" retries="0" 
                      async="true"  onreturn="notifyService.onreturn" onthrow="notifyService.onthrow"></dubbo:method>
    </dubbo:reference>
     
    测试结果输出:
    main方法直接返回的结果:null
    ======onreturn======, param: world, result: Hello world, response form provider: 192.168.215.1:20880

    注意:如果上面使用的是异步,则返回的结果为null

     
    二、源码分析
     
     
    整个事件通知的逻辑都在FutureFilter中,来看一下源码:
    public Result invoke(final Invoker<?> invoker, final Invocation invocation) throws RpcException {
        final boolean isAsync = RpcUtils.isAsync(invoker.getUrl(), invocation);
        // 1 调用服务之前:执行xxxService.oninvoke方法
        fireInvokeCallback(invoker, invocation);
        // need to configure if there's return value before the invocation in order to help invoker to judge if it's
        // necessary to return future.
        // 2 调用服务
        Result result = invoker.invoke(invocation);
        // 3 调用服务之后
        if (isAsync) {
            asyncCallback(invoker, invocation);
        } else {
            syncCallback(invoker, invocation, result);
        }
        // 4 返回调用结果
        return result;
    }
    fireInvokeCallback
    反射执行xxxService.oninvoke方法:必须具有与真实的被调用方法sayHello相同的入参列表。
    private void fireInvokeCallback(final Invoker<?> invoker, final Invocation invocation) {
        final Method onInvokeMethod = (Method) StaticContext.getSystemContext().get(StaticContext.getKey(invoker.getUrl(), invocation.getMethodName(), Constants.ON_INVOKE_METHOD_KEY));
        final Object onInvokeInst = StaticContext.getSystemContext().get(StaticContext.getKey(invoker.getUrl(), invocation.getMethodName(), Constants.ON_INVOKE_INSTANCE_KEY));
    
        if (onInvokeMethod == null && onInvokeInst == null) {
            return;
        }
        if (onInvokeMethod == null || onInvokeInst == null) {
            throw new IllegalStateException("service:" + invoker.getUrl().getServiceKey() 
                                            + " has a onreturn callback config , but no such " + (onInvokeMethod == null ? "method" : "instance") 
                                            + " found. url:" + invoker.getUrl());
        }
        if (onInvokeMethod != null && !onInvokeMethod.isAccessible()) {
            onInvokeMethod.setAccessible(true);
        }
        // 获取真实方法sayHello传入的参数
        Object[] params = invocation.getArguments();
        try {
            onInvokeMethod.invoke(onInvokeInst, params);
        } catch (InvocationTargetException e) {
            fireThrowCallback(invoker, invocation, e.getTargetException());
        } catch (Throwable e) {
            fireThrowCallback(invoker, invocation, e);
        }
    }
     
    再来看一下同步调用和异步调用
    private void asyncCallback(final Invoker<?> invoker, final Invocation invocation) {
        Future<?> f = RpcContext.getContext().getFuture();
        if (f instanceof FutureAdapter) {
            ResponseFuture future = ((FutureAdapter<?>) f).getFuture();
            // 3.1 调用服务之后:设置回调ResponseCallback对象到DefaultFuture中,
            // 当provider返回响应时,执行DefaultFuture.doReceived方法,该方法会调用ResponseCallback对象的done或者caught方法
            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 syncCallback(final Invoker<?> invoker, final Invocation invocation, final Result result) {
        if (result.hasException()) {
            //3.1 调用服务之后:如果返回结果异常信息(注意:如果是consumer自己throw的异常,会在2的时候直接抛走,不会走到这里),直接执行xxxService.onthrow方法
            fireThrowCallback(invoker, invocation, result.getException());
        } else {
            //3.2 调用服务之后:如果返回值正常,执行xxxService.onreturn方法
            fireReturnCallback(invoker, invocation, result.getValue());
        }
    }
     
     
    异步与同步的区别
     
     
  • 相关阅读:
    5 输出的properties文件按照key进行排序
    JFinal 部署在 Tomcat 下推荐方法(转)
    15个必须知道的chrome开发者技巧(转)
    一次完整的浏览器请求流程(转)
    工作第一天
    Struts2的crud
    equal 和 ==
    生成Apk遇到的问题
    Http Framework
    Gradle: The New Android Build System
  • 原文地址:https://www.cnblogs.com/caoxb/p/13140375.html
Copyright © 2020-2023  润新知