04 AOP学习之通知参数

Spring AOP通知参数

前边章节已经介绍了声明通知,但如果想获取被被通知方法参数并传递给通知方法,该如何实现呢?接下来我们将介绍两种获取通知参数的方式。

1. 使用JoinPoint获取

Spring AOP提供使用org.aspectj.lang.JoinPoint类型获取连接点数据,任何通知方法的第一个参数都可以是JoinPoint(环绕通知是ProceedingJoinPoint,JoinPoint子类),当然第一个参数位置也可以是JoinPoint.StaticPart类型,这个只返回连接点的静态部分。

  1. JoinPoint:提供访问当前被通知方法的目标对象、代理对象、方法参数等数据:

    public interface JoinPoint {
    
        String toString();                  //连接点所在位置的相关信息  
        String toShortString();             //连接点所在位置的简短相关信息  
        String toLongString();              //连接点所在位置的全部相关信息
        Object getThis();                   //返回AOP代理对象,如果想要使用这个方法的话,最好使用this连接点,这样可以获得最佳的性能。  
        Object getTarget();                 //返回目标对象,如果想要使用这个方法的话,最好使用target连接点,这样可以获得最佳的性能。
        Object[] getArgs();                 //返回被通知方法参数列表  
        Signature getSignature();           //返回当前连接点签名  
        SourceLocation getSourceLocation(); //返回连接点方法所在类文件中的位置  
        String getKind();                   //连接点类型  
        StaticPart getStaticPart();         //返回连接点静态部分  
    
        // getKind 方法的返回值
        static String METHOD_EXECUTION = "method-execution";
        static String METHOD_CALL = "method-call";
        static String CONSTRUCTOR_EXECUTION = "constructor-execution";
        static String CONSTRUCTOR_CALL = "constructor-call";
        static String FIELD_GET = "field-get";
        static String FIELD_SET = "field-set";
        static String STATICINITIALIZATION = "staticinitialization";
        static String PREINITIALIZATION = "preinitialization";
        static String INITIALIZATION = "initialization";
        static String EXCEPTION_HANDLER = "exception-handler";
        static String SYNCHRONIZATION_LOCK = "lock";
        static String SYNCHRONIZATION_UNLOCK = "unlock";
        static String ADVICE_EXECUTION = "adviceexecution"; 
    }
    
  2. ProceedingJoinPoint:用于环绕通知,使用proceed()方法来执行目标方法:

public interface ProceedingJoinPoint extends JoinPoint {  
    void set$AroundClosure(AroundClosure arc);              // 这是个内部方法,不应该直接调用
    public Object proceed() throws Throwable;               // 执行目标函数,以默认的参数执行
    public Object proceed(Object[] args) throws Throwable;  // 执行目标函数,并传入所需的参数
}  
  1. JoinPoint.StaticPart:提供访问连接点的静态部分,如被通知方法签名、连接点类型等:
public interface StaticPart {
    Signature getSignature();           // 返回当前连接点签名
    SourceLocation getSourceLocation(); // 返回连接点所在资源路径
    String getKind();                   // 连接点类型
    int getId();                        // 唯一标识 
    String toString();                  // 连接点所在位置的相关信息
    String toShortString();             // 连接点所在位置的简短相关信息
    String toLongString();              // 连接点所在位置的全部相关信息
}

如果使用该种方式声明参数,必须放到方法第一个位置上,如

@Aspect
@Component
public class JoinPointAop {

    // 切点范围
    @Pointcut("execution(* com.learn.service..IJoinPointService+.*(..))")
    public void pointcut(){ }

    @Before("pointcut()")
    public void before1(JoinPoint jp) {
        System.out.println("---------------@Before1----------------");
        System.out.println(Arrays.toString(jp.getArgs()));
    }

    @Before("pointcut()")
    public void before2(JoinPoint.StaticPart jp) {
        System.out.println("---------------@Before2----------------");
        System.out.println(jp.getSignature());
    }

    @Around("pointcut()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("---------------@Around----------------");
        return pjp.proceed();
    }

}

2. 手动指定

通过切入点表达式可以将相应的参数自动传递给通知方法。

在Spring AOP中,除了execution和bean指示符不能传递参数给通知方法,其他指示符都可以将匹配的相应参数或对象自动传递给通知方法。

简单使用

例:

@Before(value="execution(* com.learn.service..IAppointService+.say(*)) && args(param)", argNames="param") //明确指定了
public void before1(String param) {
    System.out.println("===param:" + param);
}

切入点表达式execution( com.learn.service..IAppointService+.say()) && args(param)**:

  1. 首先execution(* com.learn.service..IAppointService+.say(*))匹配IAppointService接口的实现类的say方法,且有一个任何类型的参数;
  2. args(param)将首先查找通知方法上同名的参数,并在方法执行时(运行时)匹配传入的参数是使用该同名参数类型,即java.lang.String;如果匹配将把该被通知参数传递给通知方法上同名参数。
    其中argNames可以省略不写,但是省略的话如果在class文件中没生成变量调试信息是获取不到方法参数名字的
  3. 如果想使用JoinPoint当做参数的话,也需要在argNames中指定,如:
    @Before(value="execution(* com.learn.service..IAppointService+.say(*)) && args(param)", argNames="jp, param") //明确指定了
    public void before1(JoinPoint jp, String param) {
        System.out.println("===JoinPoint:" + jp.getKind());
        System.out.println("===param:" + param);
    }
    

组合使用

@Before(value = "pointcut() && args(param) && this(service) && @annotation(secure)", argNames = " jp, param, service, secure")
public void before2(JoinPoint jp, String param, IAppointService service, Secure secure) {
    service.logInfo("==before==");
    System.out.println("===JoinPoint:" + jp.getKind());
    System.out.println("===param:" + param);
    System.out.println("===secure:" + secure.value());
}

也可以使用引用切入点的方式获取参数:

@Pointcut(value = "args(param)", argNames = "param")
private void pointcut1(String param) {
}

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

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,646评论 18 139
  • Via http://jinnianshilongnian.iteye.com/blog/1415606 http...
    xiaobinZh阅读 1,561评论 0 52
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,608评论 18 399
  • 此刻,我躺在老家的热炕上,看冬日的雪花飘飘洒洒从天而降。 雪花是冬天的精灵,落雪的午后,气温虽低却没有刺...
    魏文晶阅读 223评论 0 2
  • 1989年,索尼公司的创始人之一盛田昭夫,斥资48亿美元,对美国哥伦比亚电影公司及关联公司进行并购。哥伦比亚电影公...
    刘远鑫阅读 995评论 0 1