spring-AOP之通知和顾问
通知和顾问都是切面的实现形式,其中通知可以完成对目标对象方法简单的织入功能。
而顾问包装了通知,可以让我们对通知实现更加精细化的管理,让我们可以指定具体的切入点。
通知分为前置通知,环绕通知及后置通知。
前置通知:在目标方法执行之前执行,不改变方法的执行流程及执行结果,前置通知的实现类要实现“MethodBeforeAdvice”这个接口。
环绕通知:也叫方法拦截器,可以改变方法的执行流程及执行结果,环绕通知的实现类要实现“MethodInterceptor”这个接口。
后置通知:在目标方法执行之后执行,不改变方法的执行流程及执行结果,后置通知的实现类要实现“AfterReturningAdvice”这个接口。
为了说明以上三者的区别,我们还是用实验来说明,这次的实例是实现一个计算器,有加法和除法。
首先是计算器的接口。
public interface ICalculatorService {
int add(int a,int b);
int division(int a ,int b);
}
实现类:
public class CalculatorServiceImpl implements ICalculatorService {
@Override
public int add(int a, int b) {
return a+b;
}
@Override
public int division(int a, int b) {
return a/b;
}
}
前置通知的实现类:
public class TestMethodBeforeAdive implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println("执行前置通知--->"+"正在执行的方法名为"+method.getName());
}
}
环绕通知的实现类:
public class TestMethodInterceptor implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("执行环绕通知--->"+"正在执行的方法名为"+invocation.getMethod().getName());
Object[] arguments = invocation.getArguments();
int a = (int)arguments[0];
int b = (int)arguments[1];
if(b == 0){
System.err.println("除数不能为0");
return -1;
}
if(a == 0){
return 0;
}
return invocation.proceed();
}
}
后置通知的实现类:
public class TesAfterRunningAdive implements AfterReturningAdvice {
@Override
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
System.out.println("执行后置通知--->"+"正在执行的方法名为"+method.getName());
System.err.println("执行结果为:"+returnValue.toString());
}
}
xml的配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:task="http://www.springframework.org/schema/task" xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd"> <!-- 目标对象 -->
<bean id="calculatorServiceTarget" class="com.opensource.service.impl.CalculatorServiceImpl"/>
<!-- 通知 -->
<bean id="methodBeforeAdive" class="com.opensource.service.impl.TestMethodBeforeAdive"/>
<bean id="afterRunningAdive" class="com.opensource.service.impl.TesAfterRunningAdive"/>
<bean id="methodInterceptor" class="com.opensource.service.impl.TestMethodInterceptor"/> <!-- 代理对象 -->
<bean id="proxyFactoryBean" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="calculatorServiceTarget"/>
<property name="interfaces" value="com.opensource.service.ICalculatorService"/>
<property name="interceptorNames">
<list>
<value>methodBeforeAdive</value>
<value>afterRunningAdive</value>
<value>methodInterceptor</value>
</list>
</property>
</bean>
</beans>
测试类:
public class MyTest {
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext("spring-bean.xml");
ICalculatorService bean = (ICalculatorService)ac.getBean("proxyFactoryBean");
int division = bean.division(10, 0);
System.out.println("两数相除商为:"+division);
//bean.add(0, 2);
}
}
实验结果:

使用通知这种切面对目标对象的方法进行织入的缺点是是显而易见的,因为他会对目标对象中的所有方法进行织入。如上例中,我们定义的环绕通知这个切面只是用来对目标对象中的"division"这一方法进行织入而对“add”方法,不加织入。但使用通知进行织入的话,会把目标对象中所有的方法都进行了织入。也就是说目标对象中所有的方法都成为了切入点。要实现对通知更加精细化的管理,就要引入顾问,可以让我们有选择性的对目标对象的方法进行织入。
如上例中,我们希望环绕通知只对目标对象的“division”方法进行织入,那么使用顾问就可以这么做(这里我们使用NameMatchMethodPointcutAdvisor这种顾问):
修改配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:task="http://www.springframework.org/schema/task" xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd"> <!-- 目标对象 -->
<bean id="comparatorServiceTarget" class="com.opensource.service.impl.ComparatorServiceImpl"/>
<bean id="calculatorServiceTarget" class="com.opensource.service.impl.CalculatorServiceImpl"/>
<!-- 通知 -->
<bean id="methodBeforeAdive" class="com.opensource.service.impl.TestMethodBeforeAdive"/>
<bean id="afterRunningAdive" class="com.opensource.service.impl.TesAfterRunningAdive"/>
<bean id="methodInterceptor" class="com.opensource.service.impl.TestMethodInterceptor"/>
<!-- 顾问 -->
<bean id="advisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
<property name="advice" ref="methodInterceptor"/>
<property name="mappedNames" value="division"/>
</bean>
<!-- 代理对象 -->
<bean id="proxyFactoryBean" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="calculatorServiceTarget"/>
<property name="interfaces" value="com.opensource.service.ICalculatorService"/>
<property name="interceptorNames">
<list>
<value>methodBeforeAdive</value>
<value>afterRunningAdive</value>
<value>advisor</value>
</list>
</property>
</bean>
</beans>
测试类:
public class MyTest {
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext("spring-bean.xml");
ICalculatorService bean = (ICalculatorService)ac.getBean("proxyFactoryBean");
/*int division = bean.division(10, 0);
System.out.println("两数相除商为:"+division);*/
int add = bean.add(0, 2);
System.out.println("两数想加和为:"+add);
}
}
实验结果:

另外在顾问中对多个切入点进行指定的时候可以使用逗号隔开,还有可以使用模糊匹配的方式例如“query*”这种方式。
分析以上的使用方式我们会发现两个缺点
1):由于我们的代理对象是由ProxyFactoryBean工具类生成的,这就决定了一个代理对象只能代理一个目标对象,当有多个目标对象时,就需要有多个代理对象,这样就很麻烦。
2):我们在测试类中获取bean时,用的是代理对象的id获取的,不是通过我们定义的目标对象的id来获取的,我们真正想要的是目标对象,而不是代理对象。
spring-AOP之通知和顾问的更多相关文章
- Spring笔记07(Spring AOP的通知advice和顾问advisor)
1.Spring AOP的通知advice 01.接口代码: package cn.pb.dao; public interface UserDao { //主业务 String add(); //主 ...
- Spring AOP 四大通知
Spring AOP 四大通知 Spring 3.X 以前 1.前置通知,实现 MethodBeforeAdvice 接口,重写 public void before(Method metho ...
- spring aop 环绕通知around和其他通知的区别
前言: spring 的环绕通知和前置通知,后置通知有着很大的区别,主要有两个重要的区别: 1) 目标方法的调用由环绕通知决定,即你可以决定是否调用目标方法,而前置和后置通知 是不能决定的,他们只 ...
- spring aop环绕通知
[Spring实战]—— 9 AOP环绕通知 假如有这么一个场景,需要统计某个方法执行的时间,如何做呢? 典型的会想到在方法执行前记录时间,方法执行后再次记录,得出运行的时间. 如果采用Sprin ...
- Spring AOP前置通知和后置通知
Spring AOP AspectJ:Java社区里最完整最流行的AOP框架 在Spring2.0以上的版本中,可以使用基于AspectJ注解或基于XML配置的AOP 在Spring中启用Aspect ...
- Spring AOP高级——源码实现(2)Spring AOP中通知器(Advisor)与切面(Aspect)
本文例子完整源码地址:https://github.com/yu-linfeng/BlogRepositories/tree/master/repositories/Spring%20AOP%E9%A ...
- spring7——AOP之通知和顾问
通知和顾问都是切面的实现形式,其中通知可以完成对目标对象方法简单的织入功能. 而顾问包装了通知,可以让我们对通知实现更加精细化的管理,让我们可以指定具体的切入点. 通知分为前置通知,环绕通知及后置通知 ...
- [转载] spring aop 环绕通知around和其他通知的区别
前言: spring 的环绕通知和前置通知,后置通知有着很大的区别,主要有两个重要的区别: 1) 目标方法的调用由环绕通知决定,即你可以决定是否调用目标方法,而前置和后置通知 是不能决定的,他们只 ...
- Spring AOP前置通知实例说明AOP相关概念
今天又看了下韩顺平的SpringAOP的讲解,讲解的很透彻.仿照视频自己使用下前置通知. 一.引出问题 有个接口TestServiceInter,有两个实现方法TestService和Test2Ser ...
- Spring AOP前置通知实例讲解与AOP详细解析
一.引出问题 有个接口TestServiceInter,有两个实现方法TestService和Test2Service.他们都有sayHello():我们的需求是在调用这两个方法之前,要先完成写日志的 ...
随机推荐
- 神州数码OSPF路由汇总配置
实验要求:掌握OSPF路由汇总配置 拓扑如下 R1 enable 进入特权模式 config 进入全局模式 hostname R1 修改名称 interface s0/1 进入端口 ip addres ...
- 小程序仿QQ侧滑例子
缩放:wxml <!--page/one/index.wxml--> <view class="page"> <view class="pa ...
- SSH设置秘钥登录
设置 SSH 通过密钥登录 我们一般使用 PuTTY 等 SSH 客户端来远程管理 Linux 服务器.但是,一般的密码方式登录,容易有密码被暴力破解的问题.所以,一般我们会将 SSH 的端口设置为默 ...
- Python全栈之路----Python2与Python3
金角大王Alex python 之路,致那些年,我们依然没搞明白的编码 python2与python3的区别 py2 str = bytes 为什么有bytes? 是因为要表示图片.视频等二进制格式 ...
- python学习之路08——元组、集合
一. 元组 1.概念 列表:是一种有序的集合 元组和列表的区别: a.列表:[] 元组:() b.列表中的元素可以进行增加和删除操作,但是,元组中的元素不能进行修改 c.相同点:都是一种容 ...
- (26)基于cookie的登陆认证(写入cookie、删除cookie、登陆后所有域下的网页都可访问、登陆成功跳转至用户开始访问的页面、使用装饰器完成所有页面的登陆认证)
获取cookie request.COOKIES['key'] request.get_signed_cookie(key, default=RAISE_ERROR, salt='', max_age ...
- C# EasyHook MessageBox 示例(极简而全)
完整代码,原创无藏私,绝对实用.Windows10 X64 下调试通过,对 w3wp.exe, sqlserver.exe,notepad.exe,iexporer.exe 注入后,长时间运行稳定,未 ...
- Java中的接口和抽象类
接口和抽象类是Java设计中最基本的概念,它们都不能实例化对象,都可以实现多态,也都能用来创建匿名内部类.但实际使用上还有很多的不同. 两者的语法定义不同,对应的设计抽象关系也不同,接口主要是对行为的 ...
- 一 Struts框架(上)
Struts2 是基于MVC的WEB框架 经过六年多的发展,Struts1已经成为了一个高度成熟的框架,不管是稳定性还是可靠性都得到了广泛的证明.市场占有率超过20%,拥有丰富的开发人群,几乎已经成为 ...
- InnoDB引擎体系架构
InnoDB引擎架构介绍 innodb存储引擎的体系架构,可简单划分成三层: 数据文件 :磁盘上的数据文件 内存池:缓存磁盘上的数据,方便读取,同时在对磁盘文件数据修改之前在这里缓存,然后按一定规刷新 ...