dubbo中的事件通知

/ Dubbo / 2 条评论 / 835浏览

我们在使用dubbo服务时,有一种可能是在调用服务时抛出了异常,因为是服务提供方抛出的异常,所以我们服务调用方是没有办法处理的,这在安全级别比较高的场景中是有很大的安全隐患的。为了解决这样的问题,dubbo中提供了事件通知功能,也就是在调用服务时例如:在调用之前、调用之后、抛出异常时都会触发相应的dubbo提供的oninvoke 、 onreturn 、 onthrow 三个事件,我们可以手动的配置任何一个类实现这3个事件方法,并且在抛出异常时,可以让服务调用方有办法处理相关业务。


由于dubbo中的事件通知功能是在服务调用方处理的,所以我们现在直接看一下服务调用方的代码,而有关服务提供方的代码配置,我们将在文章的最后上传项目源码,请在项目源码中查看。按照上面介绍的应该创建一个接口来添加上面3个事件的方法,并且创建相应的实现类来处理相关业务。

Callback:

/**
 * 服务消费者回调接口
 */
public interface Callback {

    void oninvoke(UserInfo userInfo);

    void onreturn(UserInfo userInfo);

    void onthrow(Throwable throwable);

}

接口的实现类,因为我们只是演示事件通知功能,所以我们只是简单的输出的信息,而没有做任何处理,在实际的开发中,应该做相应的业务处理。

CallbackImpl:

/**
 * 服务消费者回调接口实现类
 */
@Service
public class CallbackImpl implements Callback {

    public void oninvoke(UserInfo userInfo) {
        System.out.println(String.format("oninvoke:\t%s", userInfo));
    }

    public void onreturn(UserInfo userInfo) {
        System.out.println(String.format("onreturn:\t%s", userInfo));
    }

    public void onthrow(Throwable throwable) {
        System.out.println(String.format("throwable:\t%s", throwable));
    }
}

因为在使用事件通知功能时,是需要指定哪个接口去处理oninvoke 、 onreturn 、 onthrow 等三个事件,所以在服务调用方的配置与以往配置优些不同,需要配置处理上述事件的接口。

consumer.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://code.alibabatech.com/schema/dubbo
       http://code.alibabatech.com/schema/dubbo/dubbo.xsd">

    <!-- 调用方信息-->
    <dubbo:application name="jilinwula"/>

    <!-- 使用zookeeper查找服务地址 -->
    <dubbo:registry address="127.0.0.1:2181" protocol="zookeeper"/>

    <bean id="callback" class="com.jilinwula.consumer.CallbackImpl"/>

    <!-- Dubbo自动生成远程服务代理 -->
    <dubbo:reference id="userInfoService" interface="com.jilinwula.api.UserInfoService">
        <dubbo:method name="get" async="true" oninvoke="callback.oninvoke" onreturn="callback.onreturn" onthrow="callback.onthrow"/>
    </dubbo:reference>

</beans>

测试类:

/**
 * 服务调用方
 */
public class Consumer {
    public static void main(String[] args) throws Exception {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"consumer.xml"});
        context.start();

        UserInfoService userInfoService = context.getBean("userInfoService", UserInfoService.class);

        System.out.println(String.format("userInfoService:%s", userInfoService.get("吉林乌拉")));    }
}

日志:

userInfoService:null
2018-08-21 17:26:28:933 INFO [ProductBossService,com.alibaba.dubbo.config.AbstractConfig$1,81]:  [DUBBO] Run shutdown hook now., dubbo version: 2.6.2, current host: 192.168.5.179
2018-08-21 17:26:28:933 INFO [ProductBossService,com.alibaba.dubbo.registry.support.AbstractRegistryFactory,64]:  [DUBBO] Close all registries [zookeeper://127.0.0.1:2181/com.alibaba.dubbo.registry.RegistryService?application=jilinwula&dubbo=2.6.2&interface=com.alibaba.dubbo.registry.RegistryService&pid=19684×tamp=1534843587657], dubbo version: 2.6.2, current host: 192.168.5.179
2018-08-21 17:26:28:933 INFO [ProductBossService,com.alibaba.dubbo.registry.support.AbstractRegistry,451]:  [DUBBO] Destroy registry:zookeeper://127.0.0.1:2181/com.alibaba.dubbo.registry.RegistryService?application=jilinwula&dubbo=2.6.2&interface=com.alibaba.dubbo.registry.RegistryService&pid=19684×tamp=1534843587657, dubbo version: 2.6.2, current host: 192.168.5.179
2018-08-21 17:26:28:934 INFO [ProductBossService,com.alibaba.dubbo.registry.support.AbstractRegistry,284]:  [DUBBO] Unregister: consumer://192.168.5.179/com.jilinwula.api.UserInfoService?application=jilinwula&category=consumers&check=false&dubbo=2.6.2&get.async=true&interface=com.jilinwula.api.UserInfoService&methods=get&pid=19684&side=consumer×tamp=1534843587471, dubbo version: 2.6.2, current host: 192.168.5.179
onreturn:    UserInfo{username='吉林乌拉', password='jilinwula.com'}

我们看日志输出,userInfoService输出的结果居然是null,而onreturn返回服务提供者的信息。这是为什么呢?这是因为我们在配置文件中配置了async="true"该参数的的作用是异步回调,所以,我们直接调用接口时,是不会返回信息的,而是将返回的信息,放到了onreturn事件中。下面我们将async修改为false,也就是async="false",来在看一下程序运行结果。

consumer.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://code.alibabatech.com/schema/dubbo
       http://code.alibabatech.com/schema/dubbo/dubbo.xsd">

    <!-- 调用方信息-->
    <dubbo:application name="jilinwula"/>

    <!-- 使用zookeeper查找服务地址 -->
    <dubbo:registry address="127.0.0.1:2181" protocol="zookeeper"/>

    <bean id="callback" class="com.jilinwula.consumer.CallbackImpl"/>

    <!-- Dubbo自动生成远程服务代理 -->
    <dubbo:reference id="userInfoService" interface="com.jilinwula.api.UserInfoService">
        <dubbo:method name="get" async="false" oninvoke="callback.oninvoke" onreturn="callback.onreturn" onthrow="callback.onthrow"/>
    </dubbo:reference>

</beans>

日志:

onreturn:    UserInfo{username='吉林乌拉', password='jilinwula.com'}
userInfoService:UserInfo{username='吉林乌拉', password='jilinwula.com'}

这样当我们直接调用方法时,会立刻返回服务提供方的结构,并且onreturn事件中也会包括返回的信息。下面我们估计在服务提供者抛出,异常,看看一下日志输出。

UserInfoServiceImpl:

/**
 * 服务实现类
 */
@Service
public class UserInfoServiceImpl implements UserInfoService {
    public UserInfo get(String username) {
        System.out.println(1 / 0);
        return new UserInfo("吉林乌拉", "jilinwula.com");
    }
}

日志:

throwable:    java.lang.ArithmeticException: / by zero

我们看日志throwable事件已经成功的获取了异常的信息了。在实际的开发中,我们就可以将安全性比较高服务出现异常时的处理业务写到throwable事件中。


这就是dubbo中的事件通知的功能,如有考虑不周到或者有想交流的,可能随时留言,谢谢。

项目源码

  1. 请问一下,你配置oninvoke是成功的吗?为什么我配置了,就报No bean named 'eventImpl.oninvoke' is defined这个错误

    回复
    1. @linmoo

      恩,这个确实有问题,所以本篇文章中,没有介绍oninvoke,准备以后重新写一篇,关于oninvoke的。初步怀疑报错的原因是dubbo版本更新导致的

      回复