前言

本文主要跟大家分享介绍了关于Spring AOP中@Aspect的高级用法,下面话不多说了,来随着小编一起看看详细的介绍吧。

1 切点复合运算

支持在切点定义中加入以下运算符进行复合运算:

运算符

说明

&&

与运算。

!

非运算。

||

或运算。

2 切点命名

一般情况下,切点是直接声明在需要增强方法处,这种切点的声明方式称为匿名切点,匿名切点只能在声明处被使用 。 如果希望在其它地方可以重用这个切点,我们可以通过 @Pointcut 注解及切面类方法来命名它。

public class NamePointcut {

/**

* 切点被命名为 method1,且该切点只能在本类中使用

*/

@Pointcut("within(net.deniro.spring4.aspectj.*)")

private void method1() {

}

/**

* 切点被命名为 method2,且该切点可以在本类或子孙类中使用

*/

@Pointcut("within(net.deniro.spring4.aspectj.*)")

protected void method2() {

}

/**

* 切点被命名为 method3,且该切点可以在任何类中使用

* 这里还使用了复合运算

*/

@Pointcut("method1() && method2()")

public void method3() {

}

}

命名切点的结构如下:

切点可访问性修饰符与类可访问性修饰符的功能是相同的,它可以决定定义的切点可以在哪些类中可使用。

因为命名切点仅利用方法名及访问修饰符的信息,所以我们一般定义方法的返回类型为 void ,并且方法体为空 。

定义好切点后,就可以在切面类中引用啦:

@Aspect

public class NamePointcutAspect {

@After("NamePointcut.method2()")

public void aspectMethod1() {

}

/**

* 这里使用了复合运算

*/

@After("NamePointcut.method2() && NamePointcut.method3()")

public void aspectMethod2() {

}

}

3 织入顺序

一个连接点可以同时匹配多个切点,而切点所对应的增强在连接点上织入顺序的规则是这样的:

1.如果在同一个切面类中声明的增强,则按照增强在切面类中定义的顺序进行织入;

2.如果增强位于不同的切面类中,并且这些切面类都实现了org.springframework.core.Ordered 接口,则由 Ordered 方法的顺序号决定(顺序号小的先织入);

3.如果增强位于不同的切面类中,但这些切面类没有实现org.springframework.core.Ordered 接口,织入的顺序是不确定的 。

假设有两个切面类 A 与 B,它们都实现了 Ordered 接口,A 的顺序号为 1,B 的顺序号为 2,切面类 A 与 B 都定义了 3 个增强,那么同时匹配这 6 个增强的织入顺序如下图所示:

4 获取连接点信息

4.1 JoinPoint

org.aspectj.lang.JoinPoint 接口表示目标类连接点对象,它定义这些主要方法。

方法

说明

Object[] getArgs()

获取连接点方法运行时的入参列表。

Signature getSignature()

获取连接点的方法签名对象。

Object getTarget()

获取连接点所在的目标对象。

Object getThis()

获取代理对象。

4.2 ProceedingJoinPoint

org.aspectj.lang.ProceedingJoinPoint 继承了 JoinPoint 接口,它新增了两个方法(它们用于执行连接点方法)。

方法

说明

Object proceed() throws Throwable

通过反射执行目标对象连接点处的方法。

Object proceed(Object[] var1) throws Throwable

使用新的入参(替换掉原来的入参),通过反射执行目标对象连接点处的方法。

4.3 示例

Cook 接口:

public interface Cook {

/**

* 制作食品

*/

void make();

/**

* 制作

*

* @param name 食品名称

*/

void make(String name);

}

CookA 类:

public class CookA implements Cook {

public void make() {

System.out.println("制作食品");

}

public void make(String name) {

System.out.println("制作" + name);

}

}

在切面类中访问连接点信息:

@Aspect

public class JoinPointAspect {

@Around("within(net.deniro.spring4.aspectj.CookA)")

public void test(ProceedingJoinPoint pjp) throws Throwable {

System.out.println("---------获取连接点对象【开始】---------");

System.out.println("参数:" + pjp.getArgs()[0]);

System.out.println("签名对象:" + pjp.getTarget().getClass());

//执行目标对象方法

pjp.proceed();

System.out.println("---------获取连接点对象【结束】---------");

}

}

Spring bean 配置:

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xmlns:aop="http://www.springframework.org/schema/aop"

xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">

输出结果:

---------获取连接点对象【开始】---------

参数:寿司

签名对象:class net.deniro.spring4.aspectj.CookA

制作寿司

---------获取连接点对象【结束】---------

5 绑定连接点的方法入参

args()、this()、target()、@args()、@within()、@target() 和 @annotation() 这些切点函数除可以指定类名外,还可以指定参数名,将目标对象连接点上的方法入参绑定到增强的方法中 。 其中 args() 用于绑定连接点方法的入参, @annotation() 用于绑定连接点方法的注解对象,而 @args() 用于绑定连接点方法入参的注解。

CookC 类:

public class CookC implements Cook {

public void make() {

System.out.println("制作食品");

}

public void make(String name) {

System.out.println("制作" + name);

}

public void make(String name, int num) {

System.out.println("制作" + name + " " + num + " 个");

}

}

切面类:

@Aspect

public class ParamsAspect {

@Before("target(net.deniro.spring4.aspectj.CookC) && args(name,num,..)")

public void test(String name,int num) {

System.out.println("----------绑定连接点入参【开始】----------");

System.out.println("name:" + name);

System.out.println("num:" + num);

System.out.println("----------绑定连接点入参【结束】----------");

}

}

这里的连接点表达式 args(name,num,..) 会先找到 name 与 num 的类型,从而生成真正的表达式 args(String,int,..)。

增强方法可以通过 name 与 num 得到连接点的方法入参。

切点匹配和参数绑定的过程是这样的:

args()会根据参数名称在增强方法中查到名称相同的入参并获得对应参数的类型,这样就得到了匹配连接点方法的入参类型 。

连接点方法入参类型所在的位置由参数名在 args() 函数中声明的位置决定 。

上述示例中的匹配过程如下:

Spring 配置:

注意: 这里必须通过 来启用 CGLib 动态代理,这是因为 CookC 的 public void make(String name, int num) 是该类独有的方法(非接口定义的方法),所以必须使用 CGLib 生成子类的代理方法 。

单元测试:

ApplicationContext context = new ClassPathXmlApplicationContext("spring-beans.xml");

CookC cookC = (CookC) context.getBean("cookC");

cookC.make("寿司", 100);

输出结果:

----------绑定连接点入参【开始】----------

name:寿司

num:100

----------绑定连接点入参【结束】----------

制作寿司 100 个

6 绑定代理对象

使用 this() 或 target() 可绑定被代理对象的实例。通过类实例名绑定对象时,依然具有原来连接点匹配的功能,只是类名是由增强方法中的同名入参类型间接决定的。

@Aspect

public class ProxyAspect {

@Before("this(cook)")

public void bind(Cook cook) {

System.out.println("--------绑定代理对象【开始】--------");

System.out.println(cook.getClass().getName());

System.out.println("--------绑定代理对象【结束】--------");

}

}

首先通过 public void bind(Cook cook) 找出 cook 所对应的类型,接着转换切点表达式为 this(net.deniro.spring4.aspectj.Cook) 。这样就表示该切点匹配所有代理对象为 Cook 类中的所有方法。

输出结果:

--------绑定代理对象【开始】--------

net.deniro.spring4.aspectj.CookC$$EnhancerBySpringCGLIB$$217fb793

--------绑定代理对象【结束】--------

target() 绑定与 this() 相似。

7 绑定类注解对象

@within() 和 @target() 函数都可以将目标类的注解对象绑定到增强方法中。

定义一个日志注解类:

@Retention(RetentionPolicy.RUNTIME)//保留期限

@Target({ElementType.METHOD,ElementType.TYPE})//目标类型

public @interface Log {

boolean value() default true;//声明成员变量

}

把该注解类应用于 CookD:

@Log

public class CookD implements Cook {

public void make() {

System.out.println("制作糕点");

}

public void make(String name) {

}

}

绑定类注解对象:

@Aspect

public class ClassAnnotationObjectAspect {

@Before("@within(log)")

public void bind(Log log){

System.out.println("----------绑定类注解对象【开始】----------");

System.out.println(log.getClass().getName());

System.out.println("----------绑定类注解对象【结束】----------");

}

}

Spring 配置:

单元测试:

ApplicationContext context = new ClassPathXmlApplicationContext("spring-beans.xml");

CookD cook = (CookD) context.getBean("cookD");

cook.make();

输出结果:

----------绑定类注解对象【开始】----------

com.sun.proxy.$Proxy8

----------绑定类注解对象【结束】----------

从输出结果  com.sun.proxy.$Proxy8 可以看出 ,CookD 类的注解 Log 对象也被代理咯O(∩_∩)O哈哈~

8 绑定返回值

在后置增强中,可以通过 returning 来绑定连接点方法的返回值。

切面:

@Aspect

public class ReturnValueAspect {

@AfterReturning(value = "target(net.deniro.spring4.aspectj.CookA)", returning = "value")

public void bind(boolean value) {

System.out.println("绑定返回值【开始】");

System.out.println("value:" + value);

System.out.println("绑定返回值【结束】");

}

}

注意:returning 的值必须与方法参数名相同。

CookA 新增 smell 方法:

public boolean smell(String name) {

System.out.println(name + "香吗?");

return true;

}

单元测试:

ApplicationContext context = new ClassPathXmlApplicationContext("spring-beans.xml");

CookA cook = (CookA) context.getBean("cookA");

cook.smell("烤鸭");

输出结果:

烤鸭香吗?

绑定返回值【开始】

value:true

绑定返回值【结束】

9 绑定异常

可以使用 AfterThrowing 注解的 throwing 成员变量来绑定连接点抛出的异常。

切面类:

@Aspect

public class ExceptionAspect {

@AfterThrowing(value = "target(net.deniro.spring4.aspectj.CookA)",throwing = "e")

public void bind(CookException e){

System.out.println("绑定异常【开始】");

System.out.println("e:" + e.getMessage());

System.out.println("绑定异常【结束】");

}

}

注意:throwing 的值必须与方法参数名相同。

单元测试:

ApplicationContext context = new ClassPathXmlApplicationContext("spring-beans.xml");

CookA cook = (CookA) context.getBean("cookA");

cook.make("");

输出结果:

绑定异常【开始】

e:煮啥呢???

绑定异常【结束】

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对脚本之家的支持。

aspect 方法入参 获取_谈谈Spring AOP中@Aspect的高级用法示例相关推荐

  1. SpringAOP专题之6、Spring AOP中@Pointcut 12种用法

    本文主要内容:掌握@Pointcut的12种用法. Aop相关阅读 阅读本文之前,需要先掌握下面几篇篇文章内容,不然会比较吃力. 代理详解(java动态代理&CGLIB代理) jdk动态代理和 ...

  2. spring aop实现过程之三Spring AOP中Aspect编织的实现

    1.上节我们谈到拦截器起作用时,实现代码(ReflectiveMethodInvocation.java)如下: public Object proceed() throws Throwable {/ ...

  3. spring特殊字符转义和方法入参检测工具类

    由于 Web 应用程序需要联合使用到多种语言,每种语言都包含一些特殊的字符,对于动态语言或标签式的语言而言,如果需要动态构造语言的内容时,一个我们经常会碰到的问题就是特殊字符转义的问题.下面是 Web ...

  4. Spring-AOP @AspectJ进阶之绑定连接点方法入参

    文章目录 概述 实例 概述 我们前面的博文在讲解切点函数时说过args().this().target().@args().@within().@target()和@annotation()这7个函数 ...

  5. aspectj 获取方法入参_深入探索编译插桩技术(二、AspectJ)

    本文来自jsonchao的投稿,个人微信:bcce5360 现如今,编译插桩技术已经深入 Android 开发中的各个领域,而 AOP 技术正是一种高效实现插桩的模式,它的出现正好给处于黑暗中的我们带 ...

  6. aop 获取方法入参出参_ASM字节码编程 | JavaAgent+ASM字节码插桩采集方法名称及入参和出参结果并记录方法耗时...

    作者:小傅哥 博客:bugstack.cn ❝ 沉淀.分享.成长,让自己和他人都能有所收获! ❞ 一.前言 在我们实际的业务开发到上线的过程中,中间都会经过测试.那么怎么来保证测试质量呢?比如:提交了 ...

  7. 新版SpringCloudGateway网关 切面修改方法入参

    通过注解修改方法入参值,一般都是采用实现 org.springframework.web.method.support.HandlerMethodArgumentResolver 接口的 resolv ...

  8. Mybatis方法入参处理

    1,在单个入参的情况下,mybatis不做任何处理,#{参数名} 即可,甚至连参数名都可以不需要,因为只有一个参数,或者使用 Mybatis的内置参数 _parameter. 2,多个入参: 接口方法 ...

  9. 方法入参很复杂,每次调用都要构造BO入参?一招教你自动构造入参

    场景 同在互联网打工的小伙伴们肯定都面临这样一种场景: 通用逻辑(被多处调用)我们通常会封装成一个方法,那这个方法入参正常来说都不会少,(在开发规范中,经常会看到一条"方法入参正常不超过3个 ...

最新文章

  1. Openresty中使用LuaJit
  2. 配置EXCHANGE服务器
  3. python转载[编码问题]
  4. C++编译-链接错误集合
  5. MIT JOS学习笔记01:环境配置、Boot Loader(2016.10.22)
  6. Android数据存储之SQLite
  7. 20155235 《网络攻防》 实验八 Web基础
  8. BugkuCTF-Reverse题Timer(阿里CTF)
  9. 【c++ | 课上练习】2021年9月23日
  10. kubernetes failed to start sandbox
  11. RX8025 RTC闹钟唤醒Alarm_D的初始化
  12. 【盘点】2018最受欢迎的网页设计软件集合!
  13. 拜耳新一代犬体内驱虫药拜宠清登陆中国市场
  14. win10微软官网地址
  15. 如何理解图片RGB通道在python(numpy)中的数据构成
  16. [vue build Error] 在vue的图形化界面对项目进行打包时出现“Callback was already called”错误
  17. OCR图片转文字两种python方法实现
  18. 记录Cannot find class问题
  19. Storyboard Animations
  20. 对(不带头单向不循环)单链表的初步认识

热门文章

  1. 选择仓储货架时需要注意些什么?又如何预防仓储货架的倒塌?
  2. 想要拿高薪,做PLC的你必须转行上位机,可以从这两个方向发展。
  3. 属相婚配php,属鸡的属相婚配表:93年属鸡的属相婚配表?
  4. 嵌入式系统知识点总结【1-5章】
  5. linux去掉文件快捷方式,整理总结:Linux常用命令篇
  6. Java学习笔记_17 项目实战之天天酷跑(四):游戏主界面
  7. 金仓数据库KingbaseES数据库参考手册(服务器配置参数12. 客户端联接默认)
  8. 【转贴+排版】测度论简介——一个通往异世界的大门
  9. 【Hadoop】第一天 Hadoop基本概念跟原理以及安装
  10. 爬虫(17)多线程练习 图片爬取案例