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

8 advisor标签

advisor标签是需要定义在aspect标签里面的,其作用与aspect类似,可以简单的把它理解为一个特殊的切面,用于把一个Advice和一个Pointcut组合起来。一个advisor标签对应的就是一个Advisor接口的实现类,默认是DefaultBeanFactoryPointcutAdvisor实现。其使用的基本语法类似如下这样。

<aop:config>
<aop:advisor advice-ref="" pointcut-ref=""/>
</aop:config>

上面的advice-ref属性用于指定一个org.aopalliance.aop.Advice实现,该接口没有任何内容,只是起到标记作用,用于标记某个类是Advice。pointcut-ref用于指定一个通过已经存在的Pointcut定义,当然也可以直接通过pointcut属性指定对应的Pointcut表达式。如果在一个config元素下既定义了aspect,又定义了advisor,那advisor必须定义在aspect之前。接下来看一下如何通过advisor标签应用常用的5种Advice,本文旨在介绍advisor是如何用的,以及如何使用5种Advice,至于每种Advice的功能、区别啥的已经在之前的文章中已经介绍过了,就不再赘述了,有兴趣的读者请参考以前的博文。

8.1 before Advice

对应于切入点方法执行前的拦截的Advice接口是BeforeAdvice接口,这个接口也是一个空接口没有实现,我们在自定义自己的BeforeAdvice实现时不直接实现BeforeAdvice接口,而是实现MethodBeforeAdvice接口。这是Spring为了将来可以支持对类的成员变量的访问进行拦截而预留的定义,也就是说将来BeforeAdvice还会有一个基于对类的成员变量访问的拦截的子接口定义。MethodBeforeAdvice接口中定义了一个before方法,在调入目标方法前就会调用before方法。如下就是一个MethodBeforeAdvice的实现示例。

public class LogBeforeAdvice implements MethodBeforeAdvice {

	@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println("===============before advice start==============");
System.out.println("method: " + method);
System.out.println("args: " + args);
System.out.println("target: " + target);
System.out.println("===============before advice end================");
} }

定义了Advice之后,我们就可以通过advisor标签来把它和指定的PointCut绑定了。

<aop:config>
<aop:pointcut expression="bean(userService)" id="userServicePointcut"/>
<aop:advisor advice-ref="logBeforeAdvice" order="1" pointcut-ref="userServicePointcut"/>
</aop:config> <bean id="logBeforeAdvice" class="com.elim.spring.aop.advice.LogBeforeAdvice" />

8.2 around Advice

around Advice的实现需要实现org.aopalliance.intercept.MethodInterceptor接口,该接口定义了一个接收MethodInvacation类型的参数的invoke方法。通过MethodInvocation对象可以获取到目标方法、方法参数等信息,然后还可以通过调用其proceed方法来调用对应的目标方法,所以我们可以根据需要来判断是否需要调用目标方法。invoke方法的返回值将作为目标方法的调用者接收到的返回值,所以我们也可以在invoke方法中根据需要判断需要给目标方法调用者返回什么样的结果。以下是一个MethodInterceptor接口实现示例。

public class LogAroundAdvice implements MethodInterceptor {

	@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("=============================方法调用开始===" + invocation.getMethod());
try {
Object result = invocation.proceed();
System.out.println("=============================方法调用正常结束===" + invocation.getMethod());
return result;
} catch (Exception e) {
System.out.println("=============================方法调用异常===" + invocation.getMethod());
throw e;
}
} }

之前介绍基于XML配置和基于Aspectj注解的配置进行Around Advice配置时都可以在运行时根据条件来改变实际调用目标方法时传递的参数,那么如果我们直接实现MethodInterceptor接口是否又可以呢?答案是肯定的,MethodInterceptor的invoke方法参数MethodInvocation中已经封装了或者目标方法和参数的信息,如果需要改变传递的参数,我们可以不调用MethodInvocation的proceed方法,而是选择获取当前Method,然后直接调用Method的invoke方法传递自己所需要的参数。

public class LogAroundAdvice implements MethodInterceptor {

	@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("=============================方法调用开始===" + invocation.getMethod());
try {
Object result = invocation.getMethod().invoke(invocation.getThis(), 1);
System.out.println("=============================方法调用正常结束===" + invocation.getMethod());
return result;
} catch (Exception e) {
System.out.println("=============================方法调用异常===" + invocation.getMethod());
throw e;
}
} }

其配置与before advice的配置是类似的。

<aop:config>
<aop:pointcut expression="bean(userService)" id="userServicePointcut"/>
<aop:advisor advice-ref="logAroundAdvice" pointcut-ref="userServicePointcut"/>
</aop:config> <bean id="logAroundAdvice" class="com.elim.spring.aop.advice.LogAroundAdvice"/>

8.3 afterReturning Advice

AfterReturning Advice将在目标方法正常返回时触发,对应的是AfterReturningAdvice接口,其定义如下,第一个参数是目标方法的返回值。

public interface AfterReturningAdvice extends AfterAdvice {

	void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable;

}

以下是笔者的一个测试实现。

public class LogAfterReturningAdvice implements AfterReturningAdvice {

	@Override
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
System.out.println("==============调用成功返回,返回值是:" + returnValue);
System.out.println("Method: " + method);
if (returnValue instanceof User) {
//不能修改返回值,但可以修改返回值的某些属性,因为是对象引用
((User) returnValue).setName("modifyedName");
}
} }

8.4 afterThrowing Advice

afterThrowing Advice对应的Advice接口子类是ThrowsAdvice,该接口也是一个空接口,也是用于标记作用的,但是不同于BeforeAdvice定义了可供用户实现的包含方法定义的子接口MethodBeforeAdvice,ThrowingAdvice没有这样的子接口。这是因为用户可能需要同时对多种异常进行处理,如果把接口方法定义好了,那用户只能在方法体中判断当前捕获的异常类型了。没有方法定义时用户就可以在实现类中定义很多的异常处理方法了,但是这些方法也不是随便定义的,它们必须满足以下形式。其中的方法名必须为afterThrowing,方法参数只有最后一个subclassOfThrowable是必须的。

afterThrowing([Method, args, target], subclassOfThrowable)

以下是一个实现示例,在示例中我们一共实现了三个处理Exception的方法,前两个处理方法用于处理特定的异常类型,而且只接收一个异常类型参数,最后一个处理方法接收所有的参数,处理除前两者以外的其它异常。

public class LogThrowsAdvice implements ThrowsAdvice {

	/**
* 处理IllegalArgumentException
* @param e
*/
public void afterThrowing(IllegalArgumentException e) {
System.out.println("=====================方法调用异常,抛出了IllegalArgumentException");
} /**
* 处理NumberFormatException
* @param e
*/
public void afterThrowing(NumberFormatException e) {
System.out.println("=====================方法调用异常,抛出了NumberFormatException");
} /**
* 处理其它所有的异常
* @param method
* @param args
* @param target
* @param e
*/
public void afterThrowing(Method method, Object[] args, Object target, Exception e) {
System.out.println("=====================方法调用异常了," + e);
System.out.println("Method: " + method);
System.out.println("Args: " + args);
System.out.println("Target: " + target);
} }

8.5 after Advice

对于After Advice类型的Advice没有特定的接口供我们实现,如果需要自己实现一个Advice可以达到after Advice那样的效果,即无论切入点方法是否抛出异常都执行某些逻辑时,可以使用MethodInterceptor代替,在方法实现中使用try…finally形式即可。

上面配置的完整配置如下。

<aop:config>
<aop:pointcut expression="bean(userService)" id="userServicePointcut"/>
<aop:advisor advice-ref="logBeforeAdvice" order="1" pointcut-ref="userServicePointcut"/>
<aop:advisor advice-ref="logThrowsAdvice" order="2" pointcut-ref="userServicePointcut" />
<aop:advisor advice-ref="logAfterReturningAdvice" order="3" pointcut-ref="userServicePointcut"/>
<aop:advisor advice-ref="logAroundAdvice" pointcut-ref="userServicePointcut"/>
</aop:config> <bean id="logBeforeAdvice" class="com.elim.spring.aop.advice.LogBeforeAdvice" />
<bean id="logThrowsAdvice" class="com.elim.spring.aop.advice.LogThrowsAdvice" />
<bean id="logAfterReturningAdvice" class="com.elim.spring.aop.advice.LogAfterReturningAdvice" />
<bean id="logAroundAdvice" class="com.elim.spring.aop.advice.LogAroundAdvice"/>

(注:本文是基于Spring4.1.0,Elim写于2017年1月23日星期一)

Spring Aop(八)——advisor标签的更多相关文章

  1. 死磕Spring之AOP篇 - Spring AOP常见面试题

    该系列文章是本人在学习 Spring 的过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring 源码分析 GitHub 地址 进行阅读. Spring 版本:5.1 ...

  2. 死磕Spring之AOP篇 - Spring AOP注解驱动与XML配置

    该系列文章是本人在学习 Spring 的过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring 源码分析 GitHub 地址 进行阅读. Spring 版本:5.1 ...

  3. Spring AOP Example – Pointcut , Advisor

    In last Spring AOP advice examples, the entire methods of a class are intercepted automatically. But ...

  4. Spring AOP高级——源码实现(2)Spring AOP中通知器(Advisor)与切面(Aspect)

    本文例子完整源码地址:https://github.com/yu-linfeng/BlogRepositories/tree/master/repositories/Spring%20AOP%E9%A ...

  5. 关于spring aop Advisor排序问题

    关于spring aop Advisor排序问题 当我们使用多个Advisor的时候有时候需要排序,这时候可以用注解org.springframework.core.annotation.Order或 ...

  6. Spring学习(十六)----- Spring AOP实例(Pointcut(切点),Advisor)

    在上一个Spring AOP通知的例子,一个类的整个方法被自动拦截.但在大多数情况下,可能只需要一种方式来拦截一个或两个方法,这就是为什么引入'切入点'的原因.它允许你通过它的方法名来拦截方法.另外, ...

  7. Spring笔记07(Spring AOP的通知advice和顾问advisor)

    1.Spring AOP的通知advice 01.接口代码: package cn.pb.dao; public interface UserDao { //主业务 String add(); //主 ...

  8. Spring Boot 2.X(八):Spring AOP 实现简单的日志切面

    AOP 1.什么是 AOP ? AOP 的全称为 Aspect Oriented Programming,译为面向切面编程,是通过预编译方式和运行期动态代理实现核心业务逻辑之外的横切行为的统一维护的一 ...

  9. spring aop中aspect和advisor的区别

    之前看到spring AOP配置aspect(切面)有两种方式,一种是利用注解的方式配置,一种是利用XML的方式配置. 我们的配置是这样的<aop:aspect>,还有另外一种<ao ...

随机推荐

  1. hive中计算某个日期是星期几的算法

    pmod(floor((unix_timestamp('2019-06-11 00:00:00')-unix_timestamp('1970-01-05 00:00:00'))/(3600*24)), ...

  2. 2018/7/31-zznuoj-问题 A: A + B 普拉斯【二维字符串+暴力模拟+考虑瑕疵的题意-0的特例】

    问题 A: A + B 普拉斯 在计算机中,数字是通过像01像素矩阵来显示的,最终的显示效果如下:  现在我们用01来构成这些数字 当宝儿姐输入A + B 时(log10(A)<50,log10 ...

  3. 如何查看JVM的内存

    学过java的人都知道,jvm是解释运行java的,java能够作为跨平台语言,也是因为jvm的存在,合理的使用jvm内存可以帮助程序很好的运行.那么,怎么查看jvm的内存使用情况呢,下面本文介绍一下 ...

  4. windows系统上 安装 Redis

    下载地址:https://github.com/microsoftarchive/redis/releases 下载完成后,把这个给解压出来 然后,使用 cmd 命令 进入 解压的redis目录 输入 ...

  5. Java8-Executors-No.03

    import java.util.Arrays; import java.util.List; import java.util.concurrent.Callable; import java.ut ...

  6. BZOJ 1778: [Usaco2010 Hol]Dotp 驱逐猪猡 (高斯消元)

    题面 题目传送门 分析 令爆炸概率为PPP.设 f(i)=∑k=0∞pk(i)\large f(i)=\sum_{k=0}^{\infty}p_k(i)f(i)=∑k=0∞​pk​(i),pk(i)p ...

  7. js实现填写身份证号、手机号、准考证号等信息自动空格的效果

    咱们做网站的,用户体验那是相当重要的,比如12306抢票需要填写身份证,如果不空格,密密麻麻的给我一种很压抑的感觉,而且也不容易核对信息是否填写正确,所以我就写了一个利用Js实现填写身份证号.手机号. ...

  8. 选择排序之javascript

    选择排序(Selection-sort)是一种简单直观的排序算法.它的工作原理:首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放 ...

  9. dblclick([[data],fn]) 当双击元素时,会发生 dblclick 事件。

    dblclick([[data],fn]) 概述 当双击元素时,会发生 dblclick 事件.大理石量具哪家好 当鼠标指针停留在元素上方,然后按下并松开鼠标左键时,就会发生一次 click.在很短的 ...

  10. SQL Server Report Server

    1.SQL Server Report Server是利用mircosoft的share point产品 在menu 打开Reporting Services Configuration进行配置,会自 ...