转发地址: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. 什么是OAuth授权

    什么是OAuth授权?   一.什么是OAuth协议 OAuth(开放授权)是一个开放标准. 允许第三方网站在用户授权的前提下访问在用户在服务商那里存储的各种信息. 而这种授权无需将用户提供用户名和密 ...

  2. 日志分析方法概述 & Web日志挖掘分析的方法

    日志在计算机系统中是一个非常广泛的概念,任何程序都有可能输出日志:操作系统内核.各种应用服务器等等.日志的内容.规模和用途也各不相同,很难一概而论. 本文讨论的日志处理方法中的日志,仅指Web日志.其 ...

  3. ppt打不开,显示发现文件中的内容有问题。可尝试修复此演示文稿

    ppt打不开,显示发现文件中的内容有问题.可尝试修复此演示文稿 PPT发现要打开的文件有问题,修复后无法打开该文件 解决方法: 主要是因为文件是网络下载的,office自动锁定了文件(默认不可编辑). ...

  4. Vue基础认识

     一:什么是Vue? vue是一个渐进式的JavaScript框架,采用的是MVVM模式.Vue 被设计为可以自底向上逐层应用.Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整 ...

  5. HTTP权威指南与图解HTTP读书笔记

    目录 第1章 HTTP概述 1.1 Web客户端和服务器 1.2 资源 1.2.1 URI 1.2.2 URL 1.2.3 URN 1.3 事务 1.3.1 方法 1.3.2 状态码 1.3.3 We ...

  6. sql server 存储过程的详解

    SqlServer存储过程详解 1.创建存储过程的基本语法模板: if (exists (select * from sys.objects where name = 'pro_name')) dro ...

  7. 015_使用 expect 工具自动交互密码远程其他主机安装 httpd 软件

    #!/bin/bash#删除~/.ssh/known_hosts 后,ssh 远程任何主机都会询问是否确认要连接该主机rm -rf ~/.ssh/known_hostsexpect <<E ...

  8. 013_使用 user.txt 文件中的人员名单,在计算机中自动创建对应的账户并配置初始密码

    for i in `cat user.txt`do    useradd $i    echo "123456" | passwd --stdin $idone

  9. chrome扩展开发实战入门之二-自动搜索

    目标:产生随机数,用于百度搜索:像看电视一样观看搜索结果 参考上一篇,新建目录hellocrx,其中三个文件:manifest.json  content_script.js 和jquery-3.4. ...

  10. elasticsearch java动态设置mapping并指定分词器

    //创建索引 client.admin().indices().prepareCreate("twitter").execute().actionGet(); //配置mappin ...