转发地址:https://www.iteye.com/blog/elim-2395315

4 基于Aspectj注解的Advice介绍

之前介绍过,Advice一共有五种类型,分别是before、after return、after throwing、after(finally)和around。在使用注解的时候,它们对应的注解分别是@Before、@AfterReturning、@AfterThrowing、@After和@Around。 这几个注解都是在org.aspectj.lang.annotation包中。

4.1 @Before

Before Advice将在目标方法执行前执行Advice逻辑,通过它我们可以在指定的切入点方法执行前加入特定的逻辑。如下是定义的一个Before Advice,通过其value属性(注解中只指定value属性时属性名是可以省略的)指定其需要拦截的切入点id或name为userService的bean的方法执行,然后拦截后我们只是简单的打印一条语句,在实际应用中这里应该加上我们特定的逻辑。

@Before("bean(userService)")
public void before() {
System.out.println("-----before with pointcut expression: bean(userService)------");
}

注:

  • 1、@Before除了可以通过value属性指定需要拦截的切入点外,还可以指定一个argNames属性,这个是用于方便我们在Advice中访问切入点方法参数的,这个在后续会专门用一篇文章来讲如何在Advice中使用切入点方法参数。
  • 2、argNames这个属性不仅在@Before上有,在其它的Advice注解上也有。
  • 3、除非抛出异常,否则Before Advice是没法阻止程序继续往下执行的。

所有的Advice方法都可以接收一个JoinPoint参数,而且这个参数必须是Advice方法的第一个参数,通过这个参数我们可以获取到目标方法的一些信息,比如当前方法调用传递的参数信息、目标对象等。而如果是Around类型的Advice则必须接受一个ProceedingJoinPoint类型的参数,ProceedingJoinPoint是JoinPoint的子类。

@Before("bean(userService)")
public void before(JoinPoint joinPoint) {
System.out.println("-----before with pointcut expression: bean(userService)------");
joinPoint.getArgs();//获取当前目标方法调用传递的参数
joinPoint.getSignature();//获取当前目标方法的签名,通过它可以获取到目标方法名
joinPoint.getThis();//获取AOP生成的代理对象
joinPoint.getTarget();//获取被代理对象,即目标对象
System.out.println(joinPoint.getArgs());
System.out.println(joinPoint.getSignature().getName());
System.out.println(joinPoint.getThis().getClass());
System.out.println(joinPoint.getTarget().getClass());
System.out.println(joinPoint.toString());
}

4.2 @AfterReturning

AfterReturning Advice对应的是切入点方法正常执行完的拦截,即切入点方法执行时没有对外抛出异常,包括在目标方法被Around类型的Advice处理时没有抛出异常,如果目标方法在被Around类型的Advice处理时也抛出了异常,则同样会被认为目标方法是执行异常的,因为Around Advice是最先处理的,AfterReturning Advice会在Around Advice处理结束后才被触发的。如果我们希望在AfterReturning Advice中根据目标方法的返回结果做特定的业务逻辑,那么我们可以给AfterReturning Advice处理方法加一个参数,参数类型可以是你能确定的目标方法返回类型或用通用的Object,然后需要在@AfterReturning上通过returning属性指定目标方法的返回值需要赋值给AfterReturning Advice处理方法的哪个参数。如下示例中就在Advice处理方法上加入了一个通用类型的Object类型的returnValue参数,然后指定@AfterReturning的returning属性为“returnValue”。如果我们确定目标方法的返回结果一定是一个User类型的,那么我们也可以指定下面的方法参数类型是User类型。

@AfterReturning(value="bean(userService)", returning="returnValue")
public void afterReturning(Object returnValue) {
System.out.println("-----after returning with pointcut expression: bean(userService)------");
System.out.println("-----return value is: " + returnValue);
}

4.3 @AfterThrowing

AfterThrowing Advice对应的是切入点方法执行对外抛出异常的拦截。因为当一个切入点方法可以同时被Around Advice和AfterThrowing Advice拦截时,实际上AfterThrowing Advice拦截的是Around Advice处理后的结果,所以这种情况下最终AfterThrowing Advice是否能被触发,还要看Around Advice自身是否对外抛出异常,即算是目标方法对外抛出了异常,但是被Around Advice处理了又没有向外抛出异常的时候AfterThrowing Advice也不会被触发的。如果希望在AfterThrowing Advice处理方法中获取到被抛出的异常,可以给对应的Advice处理方法加一个Exception或其子类型(能确定抛出的异常类型)的方法参数,然后通过@AfterThrowing的throwing属性指定拦截到的异常对象对应的Advice处理方法的哪个参数。如下就指定了拦截到的异常对象将传递给Advice处理方法的ex参数。

@AfterThrowing(value="bean(userService)", throwing="ex")
public void afterThrowing(Exception ex) {
System.out.println("-----after throwing with pointcut expression: bean(userService)------" + ex);
}

AfterThrowing是用于在切入点方法抛出异常时进行某些特殊的处理,但是它不会阻止方法调用者看到异常结果。

4.4 @After

After Advice就相当于try…catch…finally语句里面的finally的角色,即无论被拦截的切入点方法是成功执行完成还是对外抛出了异常,对应的Advice处理方法都将会执行。

@After("bean(userService)")
public void after() {
System.out.println("-----after with pointcut expression: bean(userService)------");
}

4.5 @Around

Around Advice必须接收一个ProceedingJoinPoint类型的方法参数,然后在方法体中选择一个合适的时机来调用ProceedingJoinPoint的proceed方法以触发对目标方法的调用,然后Around Advice处理方法的返回值会被当做是目标方法调用的返回值。所以通过Around Advice我们可以在通过ProceedingJoinPoint调用目标方法的前后加上特定的逻辑,包括使用try…catch…finally等,所以Around Advice是功能最强大的一个Advice,前面的任何一种Advice在应用的时候都可以被Around Advice替换。

@Around("bean(userService)")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("-----around with pointcut expression: bean(userService)------");
System.out.println("---------------------调用前---------------------");
Object result = pjp.proceed();
System.out.println("---------------------调用后---------------------");
return result;
}

在上面的示例中我们就通过Around Advice拦截了id或name为userService的bean的所有方法调用,把真实的目标方法的返回结果返回去了。而实际上我们这里还可以修改目标方法的返回结果,比如常用的就是Spring的缓存会通过Around Advice在调用目标方法前先从缓存中获取结果,如果获取到了则直接返回。这也是Around Advice跟AfterReturning Advice一个比较大的差别,AfterReturning Advice是不能改变返回对象的引用的,但是它可以改变返回对象的个别属性。在使用Around Advice时也可以改变目标方法调用时传递的参数,这个时候要用到ProceedingJoinPoint 的带参数的proceed(Object[] args)方法了。如下示例中我们就在Around Advice中把调用目标方法的参数替换为15了。

@Around("bean(userService)")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("-----around with pointcut expression: bean(userService)------");
System.out.println("---------------------调用前---------------------");
Object[] params = new Object[]{15};
Object result = pjp.proceed(params);//可以调整目标方法调用时传递的参数
System.out.println("---------------------调用后---------------------");
return result;
}

4.6 Advice执行顺序

官方的说法是在进入切入点前优先级越高的越先执行,而在从切入点出去时优先级越高的会越后执行。当一个切面类中定义了多个Advice需要作用于同一个切入点时它们的执行顺序是不确定的,理由是无法通过反射获取到这些Advice在编译好的字节码中的声明顺序,这种情况下官方建议将多种切面逻辑整合到一个Advice中处理,以免造成错误。当两个定义在不同的切面中的Advice需要作用在同一个切入点时,除非你在切面类上使用@Order注解指定了顺序,数字越小表示优先级越高,或者是使切面类实现Ordered接口。以下是官方原文地址。 http://docs.spring.io/spring/docs/4.1.0.RELEASE/spring-framework-reference/html/aop.html#aop-ataspectj-advice-ordering

(注:本文是基于Spring4.1.0所写,写于2017年1月19日星期四)

Spring Aop(四)——基于Aspectj注解的Advice介绍的更多相关文章

  1. Spring Aop(二)——基于Aspectj注解的Spring Aop简单实现

    转发地址:https://www.iteye.com/blog/elim-2394762 2 基于Aspectj注解的Spring Aop简单实现 Spring Aop是基于Aop框架Aspectj实 ...

  2. 十四 Spring的AOP的基于AspectJ的注解开发

    Spring的AOP的基于AspectJ的注解开发 创建项目,引入jar包 编写目标类.切面类 配置目标类.切面类 在注解文件里开启AOP的开发 <?xml version="1.0& ...

  3. Spring学习之旅(八)Spring 基于AspectJ注解配置的AOP编程工作原理初探

    由小编的上篇博文可以一窥基于AspectJ注解配置的AOP编程实现. 本文一下未贴出的相关代码示例请关注小编的上篇博文<Spring学习之旅(七)基于XML配置与基于AspectJ注解配置的AO ...

  4. Spring学习之旅(七)基于XML配置与基于AspectJ注解配置的AOP编程比较

    本篇博文用一个稍复杂点的案例来对比一下基于XML配置与基于AspectJ注解配置的AOP编程的不同. 相关引入包等Spring  AOP编程准备,请参考小编的其他博文,这里不再赘述. 案例要求: 写一 ...

  5. spring-AOP框架(基于AspectJ注解配置AOP)

    基于AspectJ注解配置AOP 1.加入jar包: 要在Spring应用中使用AspectJ注解,必须在classpath下包含AspectJ类库:aopalliance.jar.aspectj.w ...

  6. day39-Spring 08-Spring的AOP:基于AspectJ的注解

    基于AspectJ的注解的开发要重点掌握. 这些表达式肯定要应用在我们的某些个增强上. 学习AspectJ也是两种形式:一种是XML,一种是注解.AspectJ的增强,就是那些通知的类型.Aspect ...

  7. 简单直白的去理解AOP,了解Spring AOP,使用 @AspectJ - 读书笔记

    AOP = Aspect Oriental Programing  面向切面编程 文章里不讲AOP术语,什么连接点.切点.切面什么的,这玩意太绕,记不住也罢.旨在以简单.直白的方式理解AOP,理解Sp ...

  8. spring AOP 之四:@AspectJ切入点标识符语法详解

    @AspectJ相关文章 <spring AOP 之二:@AspectJ注解的3种配置> <spring AOP 之三:使用@AspectJ定义切入点> <spring ...

  9. Spring AOP支持的AspectJ切入点语法大全

    原文出处:http://jinnianshilongnian.iteye.com/blog/1420691 Spring AOP支持的AspectJ切入点指示符 切入点指示符用来指示切入点表达式目的, ...

随机推荐

  1. 自定义View-----汽泡效果

    先来看一下这次要实现的最终效果: 首先来实现效果一,为实现效果二做充足的准备,下面开始: 新建工程,并定义一个自定义View,然后将其定义在布局文件中,里面是空实现,之后会一步步来填充代码: MyRi ...

  2. 2BIT

    bit是比特,是英文 binary digit的缩写.而Byte是字节又叫bait. bit是表示信息的最小单位,是二进制数的一位包含的信息或2个选项中特别指定1个的需要信息量.一般来说,n比特的信息 ...

  3. js-虚拟dom

    问题: vdom是什么?为什么存在vdom? vdom是如何应用的,核心的api是什么? 介绍一下diff算法 1.一些虚拟dom应用了snabbdom.其中的 h函数相当于渲染成了右侧的JS虚拟节点 ...

  4. Nginx命令和Nginx命令

    Nginx命令 h 查看帮助选项 V 查看版本和配置选项t 测试nginx语法错误c filename 指定配置⽂文件(default:/etc/nginx/nginx.conf)s signal 发 ...

  5. 第二章 C#语法快速热身

    C#语法快速热身 语法 if(条件表达式){ 代码块 } 语法 if(条件表达式){ 代码块 }else{ 代码块2 } 语法 if(条件表达式1){ 代码块1 if(条件表达式1)){ }else{ ...

  6. Entity Framework学习过程

    ///安装ef nuget中文控制台指令 PM> Install-Package EntityFramework.zh-Hans <!--配置数据库连接--> <connect ...

  7. 【题解】Image Perimeters-C++

    题目Description给出一张由"x"和".“组成的矩阵.每个"x"可以向上下左右及两个斜对角进行连通,请问由某个点开始的"x”,它所连 ...

  8. CF796C Bank Hacking 细节

    思路十分简单,答案只有 3 种可能,但是有一些细节需要额外注意一下. code: #include <bits/stdc++.h> #define N 300002 #define set ...

  9. Codeforces 1175E Minimal Segment Cover

    题意: 有\(n\)条线段,区间为\([l_i, r_i]\),每次询问\([x_i, y_i]\),问要被覆盖最少要用多少条线段. 思路: \(f[i][j]\)表示以\(i\)为左端点,用了\(2 ...

  10. jieba中文处理

    一:前言 和拉丁语系不同,亚洲语言是不用空格分开每个有意义的词的.而当我们进行自然语言处理的时候,大部分情况下,词汇是我们对句子和文章理解的基础,因此需要一个工具去把完整的文本中分解成粒度更细的词. ...