Spring Aop(aspect)的详细使用

AOP的基本概念

@Aspect(切面): 通常是一个类,里面可以定义切入点和通知

JointPoint(连接点):  程序执行过程中明确的点,一般是方法的调用

Advice(通知):  AOP在特定的切入点上执行的增强处理:

@Before:  标识一个前置增强方法,相当于BeforeAdvice的功能

@After:  final增强,不管是抛出异常或者正常退出都会执行。

@AfterReturning:  后置增强,似于AfterReturningAdvice, 方法正常退出时执行

@AfterThrowing:  异常抛出增强,相当于ThrowsAdvice

@Around: 环绕增强,相当于MethodInterceptor

Pointcut(切入点):   带有通知的连接点,在程序中主要体现为书写切入点表达式

AOP Proxy:AOP框架创建的对象,代理就是目标对象的加强。Spring中的AOP代理可以使JDK动态代理,也可以是CGLIB代理,前者基于接口,后者基于子类。

Pointcut配置使用:

表示式(expression)和签名(signature)

//Pointcut表示式

@Pointcut("execution(* com.savage.aop.MessageSender.*(..))")

//Point签名

private void log(){}

由下列方式来定义或者通过 &&、 ||、 !、 的方式进行组合:

execution:用于匹配方法执行的连接点;

within:用于匹配指定类型内的方法执行;

this:用于匹配当前AOP代理对象类型的执行方法;注意是AOP代理对象的类型匹配,这样就可能包括引入接口也类型匹配;        

target:用于匹配当前目标对象类型的执行方法;注意是目标对象的类型匹配,这样就不包括引入接口也类型匹配;

args:用于匹配当前执行的方法传入的参数为指定类型的执行方法;

@within:用于匹配所以持有指定注解类型内的方法;

@target:用于匹配当前目标对象类型的执行方法,其中目标对象持有指定的注解;

@args:用于匹配当前执行的方法传入的参数持有指定注解的执行;

@annotation:用于匹配当前执行方法持有指定注解的方法;

格式

execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern)throws-pattern?)

其中后面跟着“?”的是可选项

括号中各个pattern分别表示:

修饰符匹配(modifier-pattern?)

返回值匹配(ret-type-pattern)可以为*表示任何返回值,全路径的类名等

类路径匹配(declaring-type-pattern?)

方法名匹配(name-pattern)可以指定方法名 或者 *代表所有, set* 代表以set开头的所有方法

参数匹配((param-pattern))可以指定具体的参数类型,多个参数间用“,”隔开,各个参数也可以用"*" 来表示匹配任意类型的参数,".."表示零个或多个任意参数。

如(String)表示匹配一个String参数的方法;(*,String) 表示匹配有两个参数的方法,第一个参数可以是任意类型,而第二个参数是String类型

异常类型匹配(throws-pattern?)

Pointcut使用详细语法:

任意公共方法的执行:execution(public * *(..))

任何一个以“set”开始的方法的执行:execution(* set*(..))

AccountService 接口的任意方法的执行:execution(* com.xyz.service.AccountService.*(..))

定义在service包里的任意方法的执行: execution(* com.xyz.service.*.*(..))

定义在service包和所有子包里的任意类的任意方法的执行:execution(* com.xyz.service..*.*(..))

第一个*表示匹配任意的方法返回值, ..(两个点)表示零个或多个,第一个..表示service包及其子包,第二个*表示所有类, 第三个*表示所有方法,第二个..表示方法的任意参数个数

定义在pointcutexp包和所有子包里的JoinPointObjP2类的任意方法的执行:execution(* com.test.spring.aop.pointcutexp..JoinPointObjP2.*(..))")

pointcutexp包里的任意类: within(com.test.spring.aop.pointcutexp.*)

pointcutexp包和所有子包里的任意类:within(com.test.spring.aop.pointcutexp..*)

实现了Intf接口的所有类,如果Intf不是接口,限定Intf单个类:this(com.test.spring.aop.pointcutexp.Intf)

当一个实现了接口的类被AOP的时候,用getBean方法必须cast为接口类型,不能为该类的类型

带有@Transactional标注的所有类的任意方法:

@within(org.springframework.transaction.annotation.Transactional) // 亲测成功

@target(org.springframework.transaction.annotation.Transactional) // 亲测未成功

带有@Transactional标注的任意方法:@annotation(org.springframework.transaction.annotation.Transactional)

@within和@target针对类的注解,@annotation是针对方法的注解

参数带有@Transactional标注的方法:@args(org.springframework.transaction.annotation.Transactional)

参数为String类型(运行是决定)的方法: args(String)

JoinPoint 常用的方法:

Object[] getArgs:返回目标方法的参数

Signature getSignature:返回目标方法的签名

Object getTarget:返回被织入增强处理的目标对象

Object getThis:返回AOP框架为目标对象生成的代理对象

当使用@Around处理时,需要将第一个参数定义为ProceedingJoinPoint类型,该类是JoinPoint的子类。

织入

@AfterReturning(

pointcut="execution(* com.abc.service.*.access*(..)) && args(time, name)",returning="returnValue")

public void access(Date time, Object returnValue, String name){

        System.out.println("目标方法中的参数String = " + name);

        System.out.println("目标方法中的参数Date = " + time);

        System.out.println("目标方法的返回结果returnValue = " + returnValue);

}

表达式中增加了args(time, name)部分,意味着可以在增强处理的签名方法(access方法)中定义"time"和"name"两个属性。这两个形参的类型可以随意指定,但一旦指定了这两个参数的类型,则这两个形参类型将用于限制该切入点只匹配第一个参数类型为Date,第二个参数类型为String的方法(方法参数个数和类型若有不同均不匹配);access方法只需要满足"time", "name"参数的顺序和pointcut中args(param1, param2)的顺序相同即可,"returnValue"位置顺序无所谓。

//将被access方法匹配

public String accessAdvice(Date d, String n){    

    System.out.println("方法:accessAdvice");

    return"aa";

}

切面执行顺序

一个方法只被一个Aspect类拦截

正常:

异常:

同一个方法被多个Aspect类拦截

优先级高的切面类里的增强处理的优先级总是比优先级低的切面类中的增强处理的优先级高。

在“进入”连接点时,最高优先级的增强处理将先被织入(eg.给定的两个不同切面类Before增强处理中,优先级高的那个会先执行);在“退出”连接点时,最高优先级的增强处理会最后被织入(eg.给定的两个不同切面类After增强处理中,优先级高的那个会后执行)。eg.优先级为1的切面类Bean1包含了@Before,优先级为2的切面类Bean2包含了@Around,虽然@Around优先级高于@Before,但由于Bean1的优先级高于Bean2的优先级,因此Bean1中的@Before先被织入。

Spring提供了如下两种解决方案指定不同切面类里的增强处理的优先级:

让切面类实现org.springframework.core.Ordered接口:实现该接口的int getOrder()方法,该方法返回值越小,优先级越高

直接使用@Order注解来修饰一个切面类:使用这个注解时可以配置一个int类型的value属性,该属性值越小,优先级越高

同一个切面类里的两个相同类型的增强处理在同一个连接点被织入时,Spring AOP将以随机的顺序来织入这两个增强处理,没有办法指定它们的织入顺序。即使给这两个 advice 添加了 @Order 这个注解,也不行!

eg.

spring的xml配置:

进入切面的方法:

关键总结:

带有@Transactional标注的所有类的任意方法:

@within(org.springframework.transaction.annotation.Transactional) // 亲测成功

@target(org.springframework.transaction.annotation.Transactional) // 亲测未成功

带有@Transactional标注的任意方法:@annotation(org.springframework.transaction.annotation.Transactional)

@within和@target针对类的注解,@annotation是针对方法的注解

参考文献

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