通过Aspectj切面拦截Dubbo服务的执行

这可能是最手把手的dubbo框架入门中,写了一个Dubbo服务化入门的例子。dubbo-provider模块是服务提供方,其中包含了服务实现,启动时会作为服务的提供方注册到本地机器的注册中心(例子中用的是本地启动的zookeeper);dubbo-consumer是服务调用方,其启动时会远程调用注册在注册中心上的服务;dubbo-api包含了提供服务的接口,在调用服务时,需要引入这个module作为依赖。上一个例子中,已经能够成功实现了通过注册中心的远程接口调用演示。
Spring注入(IOC)和AOP实例教程中,我们写了好多切面的演示例子。在例子中,通过springaop切面和aspectj切面,都可以正确拦截本地服务的执行。
这里要介绍的是通过aspectj切面,来拦截dubbo服务的执行,并修改服务调用的参数。该例子,在这可能是最手把手的dubbo框架入门中介绍的例子之上做介绍(更具体的说,这里的例子所用的module仍然建在前面的project中)。为了演示,这里建立一个和前面例子中的dubbo-consumermodule类似的module,也是基于maven,groupid写com.spacecat.dubbo,Artifactid写dubbo-consumer-aspect
pom.xml文件如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.spacecat.dubbo</groupId>
    <artifactId>dubbo-consumer-aspect</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
        <!-- Spring Core -->
        <!-- http://mvnrepository.com/artifact/org.springframework/spring-core -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>4.1.4.RELEASE</version>
        </dependency>
        <!-- Spring Context -->
        <!-- http://mvnrepository.com/artifact/org.springframework/spring-context -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>4.1.4.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>dubbo</artifactId>
            <version>2.5.3</version>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework</groupId>
                    <artifactId>spring</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>com.spacecat.dubbo</groupId>
            <artifactId>dubbo-api</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>

        <dependency>
            <groupId>org.apache.zookeeper</groupId>
            <artifactId>zookeeper</artifactId>
            <version>3.4.10</version>
        </dependency>
        <dependency>
            <groupId>com.github.sgroschupf</groupId>
            <artifactId>zkclient</artifactId>
            <version>0.1</version>
        </dependency>



        <!-- https://mvnrepository.com/artifact/org.springframework/spring-aspects -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>5.1.8.RELEASE</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.7.4</version>
        </dependency>
    </dependencies>
</project>

写一个类,来调用前面dubbo-provider提供的服务,实际上,这个文件和之前例子中的一样。
com.dubbo.consumer.UserServiceCaller

package com.dubbo.consumer;

import com.dubbo.api.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * Created by chengxia on 2019/5/5.
 */
public class UserServiceCaller {

    public static void main(String[] args) {

        ApplicationContext context = new ClassPathXmlApplicationContext("dubbo-consumer.xml");
        UserService service = (UserService) context.getBean("userService");
        System.out.print("Got service bean:");
        System.out.println(service);
        System.out.println("RPC call output:");
        System.out.println(service.sayHi("Kobe"));
    }
}

写一个aspectj切面实现类。
com.spring.aspect.MyAspect

package com.spring.aspect;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

/**
 * Created by chengxia on 2019/8/2.
 */
@Aspect   // 表明当前POJO类是一个切面
public class MyAspect {

    // 前置通知
    @Before("execution(* com.dubbo.api..*.*(..))")
    public void myBefore(){
        System.out.println("执行前置通知方法");
    }

    // 后置通知
    @AfterReturning("execution(* com.dubbo.api..*.*(..))")
    public void myAfterReturning(){
        System.out.println("执行后置通知");
    }

    //环绕通知
    @Around("execution(* com.dubbo.api..*.*(..))")
    public Object around(ProceedingJoinPoint pjp) throws Throwable{
        System.out.println("环绕通知:目标方法执行之前");
        Object[] args = pjp.getArgs(); // 获取被切函数 参数
        args[0] = "Duncan";
        Object res = pjp.proceed(args);
        System.out.println("环绕通知:目标方法执行之后" + args[0]);
        if(res != null){
            res = ((String)res).toUpperCase();
        }
        return res;
    }
}

在这个类中实现了前置通知、后置通知以及环绕通知,在环绕通知的实现中,拦截并修改了服务调用参数的值。
最后,在配置文件dubbo-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" xmlns:aop="http://www.springframework.org/schema/aop"
       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 http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">

    <dubbo:application name="dubbo-consumer"/>
    <dubbo:registry address="zookeeper://127.0.0.1:2181"/>
    <dubbo:consumer check="false"/>

    <!-- 导入dubbo配置,dubbo-api模块打包后自带的配置文件 -->
    <import resource="classpath*:user-references.xml"/>
    <!-- 注册切面 -->
    <bean id="myAspect" class="com.spring.aspect.MyAspect"/>
    <!-- AspectJ的自动代理 -->
    <aop:aspectj-autoproxy/>
</beans>

这时候,通过如下命令启动本地的zookeeper:

$ zkServer status
ZooKeeper JMX enabled by default
Using config: /usr/local/etc/zookeeper/zoo.cfg
Error contacting service. It is probably not running.
$ zkServer start
ZooKeeper JMX enabled by default
Using config: /usr/local/etc/zookeeper/zoo.cfg
Starting zookeeper ... STARTED
$ zkServer status
ZooKeeper JMX enabled by default
Using config: /usr/local/etc/zookeeper/zoo.cfg
Mode: standalone
localhost:~ chengxia$ 

启动并运行dubbo-provider模块,然后,运行dubbo-consumer-aspect中的com.dubbo.consumer.UserServiceCaller,最后,控制台输出如下。

Got service bean:com.alibaba.dubbo.common.bytecode.proxy0@383dc82c
RPC call output:
环绕通知:目标方法执行之前
执行前置通知方法
环绕通知:目标方法执行之后Duncan
执行后置通知
HELLO DUNCAN!

Process finished with exit code 0

可以看到dubbo服务确实被切面拦截,环绕切面对服务调用参数的修改也生效了。
最后,工程的结构如下图:


aspectj切面在dubbo服务中的应用

参考资料

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,682评论 6 507
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,277评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,083评论 0 355
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,763评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,785评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,624评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,358评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,261评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,722评论 1 315
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,900评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,030评论 1 350
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,737评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,360评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,941评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,057评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,237评论 3 371
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,976评论 2 355