spring详解(九)「AOP」

定义AfterReturning增强处理

AfterReturning增强处理在目标方法正常完成之后织入。

类似于使用@Before Annotation可标注Before增强处理,使用@AfterReturning Annation来标注@AfterRetuning增强处理。
使用@AfterReturning Annotation可以指定如下属性:
<li>pointcut/value:这两个属性的作用是一样的,他们都是指定该切入点对应的切入表达式,当指定pointcut属性,value属性值将会被覆盖。
<li>returning:指定一个返回值形参,增强处理的方法可以通过该形参名来访问目标方法的返回值。

@Aspect
publicclass AfterReturningAdviceTest {
@AfterReturning(pointcut="execution(* cn.hb.spring..(..))",returning="obj")
publicvoid log(Object obj){
System.out.println("获取目标方法返回值"+obj);
System.out.println("模拟日志记录功能....");
}
}

如果log有参数,returning属性一定要配置。`如果参数不止一个,那么目标方法将不会执行必须要配置`args表达式`。`
**注意**:`使用returning属性还有另一个额外的作用:它可以限定切入点只匹配具有对应返回类型的方法。加入上面的log的参数是String类型,`则该切入点只匹配cn.hb.spring包下的返回值类型为String的所有方法。虽然AfterReturning增强处理可以访问到目标方法的返回值,但不可以改变目标方法返回值`。`

---
**定义AfterThrowing增强处理**:

>AfterThrowing增强处理主要用于程序中未处理的异常。

>使用@AfterThrowing Annotation时可以指定如下两个属性:
<li>**pointcut/value**:这两个属性的作用是一样的,他们都是指定该切入点对应的切入表达式,当指定pointcut属性,value属性值将会被覆盖。
<li>**throwing**:指定一个返回值形参名,增强处理定义的方法可以通过该形参名来访问目标方法中所抛出的异常对象。

>```
@Aspect
public class AfterThrowingAdviceTest {
    @AfterThrowing(pointcut ="execution(* cn.hb.spring.*.*(..))", throwing ="th")
    public void doRecoveryActions(Throwable th) {
        System.out.println("目标方法中抛出的异常" + th);
        System.out.println("模拟抛出异常的增强处理/.....");
    }
}
@Component
publicclass Chineseimplements Person {
@Override
publicString sayHello(String word) {
    try {
        System.out.println("sayHello方法开始执行...");
        new FileInputStream("a.txt");
    }catch (FileNotFoundException e) {
        e.printStackTrace();
    }
        return word;
}
    publicvoid eat(String food) {
        System.out.println("我正在吃" + food);
    }
    publicvoid divide(){
        int a = 5/0;
        System.out.println("divide执行完毕/"+a);
    }
}

//Chinese c = (Chinese)ac.getBean("chinese");//会出错,不能转换为Chinese
Person c = (Person)ac.getBean("chinese");
System.out.println(c.sayHello("你好--Before"));
c.eat("西瓜");
c.divide();

>**上面的程序的sayHello和divided两个方法都会抛出异常,但是sayHello方法中的异常将由该方法显示捕捉,所以Spring AOP不会处理该异常。**

>**而divide方法将抛出算术异常,且该异常没有被任何程序所处理,故Spring AOP会对该异常进行处理。**

>**使用throwing属性还有另一个作用:它可以用于限定切入点只匹配指定类型的异常。类似AfterRetuning的returning 属性。**

>Spring AOP的AfterThrowing处理虽然可以对目标方法的异常进行处理,但是这种处理与直接使用catch捕捉是不同的:
`catch意味完全处理该异常,如果catch没有重新抛出一次异常,则方法可以正常结束,而AfterThrowing处理虽然处理了异常,但它不能完全处理异常,该异常依然会传播到上一级调用者。`

---
**定义After增强处理**:
After增强处理与AfterReturning增强处理有点相似,但是也有不同:
<li>AfterRetuning只在目标方法成功完成后才被织入。
<li>After增强处理不管目标方法如何结束,都会被织入。

>因为一个方法不管是如何结束,After增强处理它都会被织入,因此After增强处理必须处理正常返回和异常返回两种情况,这种增强处理通常用于资源释放。
使用@After Annotation标注一个方法,即可将该方法转成After增强处理,使用@After Annotation增强处理需要指定一个value属性,该属性值用于指定该增强处理被织入的切入点,既可以是一个已有的切入点也可以直接指定切入点表达式。

@Aspect
publicclass AfterAdviceTest {
@After("execution(* cn.huaxia.spring..(..))")
publicvoid release(){
System.out.println("模拟方法结束后资源释放....");
}
}

**After增强处理非常类似于异常处理中的finally块的作用-----无论结果如何,它总在方法执行结束之后被织入,因此特别适合进行资源回收。**

---

** Around增强处理**:

@Around Annotation用于标注Around的增强处理,Around的增强处理是比较强的增强处理,它近似等于Before和AfterRetuning增强处理的总和,Around增强处理既可以在目标方法之前执行,也可以在执行目标方法之后织入增强动作。

与Before增强处理和AfterReturning增强处理不同的是Around增强处理可以决定目标方法执行在什么时候执行,如何执行,甚至可以阻止目标方法执行。Around增强处理可以改变执行目标方法的参数值,还可以改变执行目标方法之后的返回值。

>使用@Around Annotation时需要指定value属性,该属性用来指定该增强处理被织入的切入点。
当定义一个Around增强处理方法时,该方法的第一个形参必须是ProceedingJoinPoint类型(至少包含一个形参)。
在增强处理方法体内,调用ProceedingJoinPoint的process方法时,还可以传入一个Object[]对象,该数组中的值将被传入目标方法作为执行方法的的实参。-------这就是Around增强处理可以完全控制目标方法执行时机、如何执行的关键。`如果程序没有调用ProceedingJoinPoint的proceed方法则目标方法不会执行。`

@Aspect
publicclass AroundAdviceTest {
@Around("execution(* cn.huaxia.spring..(..))")
public Object proceedTX(ProceedingJoinPoint pre)throws Throwable {
System.out.println("开始事务.....");
Object obj = pre.proceed(new String[] {"被修改的参数" });
System.out.println("结束事务.....");
return obj +",新增的内容";
}
}

**当调用ProceedingJoinPonint的proceed方法时,传入的Object[]参数值将作为目标方法的参数,如果传入的Object[]参数的长度和目标方法参数个数不匹配,或者Object[]数组元素与目标方法所需的参数不匹配,程序就会抛出异常。
为了能获取目标方法参数的个数和类型,这就需要增强处理方法能够访问执行目标方法的参数了。**

访问目标方法的参数:

>访问目标方法最简单的的做法是定义增强处理方法时将第一个参数定义为**JoinPoint类型**,当增强处理方法被调用时,该JoinPoint参数就代表了织入增强处理的连接点,JoinPoint包含如下几个常用的方法:
    <li>Object[] getArgs():返回执行目标方法的参数;
    <li>Signature getSignature():返回被增强的方法的相关信息;
    <li>Object getTarget():返回被织入增强处理的目标方法;
    <li>Object getThis():返回AOP框架为目标对象生成的代理对象。
`如:`

@Aspect
public class FourAdviceTest {
@Around("execution(* cn.hb.spring.service..(..))")
public Object proceedTX(ProceedingJoinPoint pre) throws Throwable {
System.out.println("Around增强处理:执行目标方法前,执行模拟开启事务.......");
Object[] objs = pre.getArgs();
if (objs != null && objs.length > 0
&& objs[0].getClass() == String.class) {
objs[0] = "被修改的参数";
}
Object obj = pre.proceed(objs);
System.out.println("Around增强处理:执行目标方法之后,模拟结束事务.....");
return obj + ",新增加的内容";
}
@Before("execution(* cn.hb.spring.service..(..))")
public void authority(JoinPoint jp) {
System.out.println("Before增强:模拟权限检查");
System.out.println("Before增强:被织入增强处理的目标方法:"
+ jp.getSignature().getName());
System.out
.println("Before增强:目标方法的参数为:" + Arrays.toString(jp.getArgs()));
System.out.println("Before增强:被注入增强的处理 的目标对象:" + jp.getTarget());
}
@AfterReturning(pointcut="execution(* cn.hb.spring.service..(..))",returning="obj")
public void log(JoinPoint jp, Object obj) {
System.out.println("AfterReturning增强:获取目标方法的返回值:" + obj);
System.out.println("AfterReturning增强:模拟日志记录功能.....");
System.out.println("AfterReturning增强:被织入增强处理的目标方法:"
+ jp.getSignature().getName());
System.out.println("AfterReturning增强:目标方法的参数为:"
+ Arrays.toString(jp.getArgs()));
System.out.println("AfterReturning增强:被注入增强的处理 的目标对象:" + jp.getTarget());
}
@After("execution(* cn.huaxia.spring.service..(..))")
public void release(JoinPoint jp) {
System.out.println("After增强:模拟方法结束后,资源释放.....");
System.out.println("After增强:被织入增强处理的目标方法:"
+ jp.getSignature().getName());
System.out.println("After增强:目标方法的参数为:" + Arrays.toString(jp.getArgs()));
System.out.println("After增强:被注入增强的处理 的目标对象:" + jp.getTarget());
}
}

`输出结果:`

Around增强处理:执行目标方法之后,模拟结束事务.....
AfterReturning增强:获取目标方法的返回值:被修改的参数,新增加的内容
AfterReturning增强:模拟日志记录功能.....
AfterReturning增强:被织入增强处理的目标方法:sayHello
AfterReturning增强:目标方法的参数为:[被修改的参数]
AfterReturning增强:被注入增强的处理的目标对象:cn.hb.spring.service.Chinese2@941db6
After增强:模拟方法结束后,资源释放.....
After增强:被织入增强处理的目标方法:sayHello
After增强:目标方法的参数为:[被修改的参数]
After增强:被注入增强的处理的目标对象:cn.hb.spring.service.Chinese2@941db6
被修改的参数,新增加的内容
Around增强处理:执行目标方法前,执行模拟开启事务.......
Before增强:模拟权限检查
Before增强:被织入增强处理的目标方法:eat
Before增强:目标方法的参数为:[被修改的参数]
Before增强:被注入增强的处理的目标对象:cn.hb.spring.service.Chinese2@941db6
我正在吃:被修改的参数
Around增强处理:执行目标方法之后,模拟结束事务.....
AfterReturning增强:获取目标方法的返回值:null,新增加的内容
AfterReturning增强:模拟日志记录功能.....
AfterReturning增强:被织入增强处理的目标方法:eat
AfterReturning增强:目标方法的参数为:[被修改的参数]
AfterReturning增强:被注入增强的处理的目标对象:cn.hb.spring.service.Chinese2@941db6
After增强:模拟方法结束后,资源释放.....
After增强:被织入增强处理的目标方法:eat
After增强:目标方法的参数为:[被修改的参数]
After增强:被注入增强的处理的目标对象:cn.hb.spring.service.Chinese2@941db6
Around增强处理:执行目标方法前,执行模拟开启事务.......
Before增强:模拟权限检查
Before增强:被织入增强处理的目标方法:divide
Before增强:目标方法的参数为:[]
Before增强:被注入增强的处理的目标对象:cn.hb.spring.service.Chinese2@941db6
After增强:模拟方法结束后,资源释放.....
After增强:被织入增强处理的目标方法:divide
After增强:目标方法的参数为:[]
After增强:被注入增强的处理的目标对象:cn.hb.spring.service.Chinese2@941db6

 Spring AOP采用和AsoectJ一样的优先顺序来织入增强:**在"进入"连接点时**,最高等级的增强处理将先织入(所以给定两个Before增强处理中,优先级高的那个会执行),**在"退出"连接点时**,最高优先等级的增强处理将会最后织入。

>4个增强处理的优先等级如下(从低到高):
`Before增强处理--->Around增强处理--->AfterReturning增强处理--->After增强处理`

>当两个不同的两个增强处理需要在同一个连接点被织入时,Spring AOP将以随机的顺序来织入这两个增强处理,如果应用需要指定不同切面里增强处理的优先级,Spring提供了两个解决方案:
<li>`让切面类实现org.springframework.core.Ordered接口,实现该接口提供的 int getOrder()方法,方法返回值越小,则优先级越高。`

><li>`直接使用@Order Annotation 来标注一个切面类,使用@Order Annotation时可以指定一个int 型的value属性,该属性值越小,优先等级越高。`



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

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,585评论 18 139
  • 当相同的切面里的两个增强处理需要在相同的连接点被织入时,Spring AOP将以随机的方式来织入这两个增强处理,没...
    FTOLsXD阅读 1,255评论 0 1
  • AOP实现可分为两类(按AOP框架修改源代码的时机): 静态AOP实现:AOP框架在编译阶段对程序进行修改,即实现...
    数独题阅读 2,299评论 0 22
  • Spring Boot 参考指南 介绍 转载自:https://www.gitbook.com/book/qbgb...
    毛宇鹏阅读 46,724评论 6 342
  • 正文: 先讲个故事,这个故事我多次给同事和朋友讲过,它深深的影响了我。 80年代,高文光在天津开个一家经营五金机电...
    Kanple阅读 666评论 0 1