spring7——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来获取的,我们真正想要的是目标对象,而不是代理对象。
下篇博客将会给出这个问题的解决方法。
最后说一点,我们作为程序员,研究问题还是要仔细深入一点的。当你对原理了解的有够透彻,开发起来也就得心应手了,很多开发中的问题和疑惑也就迎刃而解了,而且在面对其他问题的时候也可做到触类旁通。当然在开发中没有太多的时间让你去研究原理,开发中要以实现功能为前提,可等项目上线的后,你有大把的时间或者空余的时间,你大可去刨根问底,深入的去研究一项技术,为觉得这对一名程序员的成长是很重要的事情。
spring7——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 AOP 四大通知 Spring 3.X 以前 1.前置通知,实现 MethodBeforeAdvice 接口,重写 public void before(Method metho ...
- spring aop环绕通知
[Spring实战]—— 9 AOP环绕通知 假如有这么一个场景,需要统计某个方法执行的时间,如何做呢? 典型的会想到在方法执行前记录时间,方法执行后再次记录,得出运行的时间. 如果采用Sprin ...
- Spring AOP前置通知实例说明AOP相关概念
今天又看了下韩顺平的SpringAOP的讲解,讲解的很透彻.仿照视频自己使用下前置通知. 一.引出问题 有个接口TestServiceInter,有两个实现方法TestService和Test2Ser ...
- AOP 环绕通知 集成了前置 后置 返回通知等功能
AOP 环绕通知 集成了前置 后置 返回通知等功能
- aop 例外通知就是记录业务方法出现错误 并保存到日志里面的功能
aop 例外通知就是记录业务方法出现错误 并保存到日志里面的功能
- Spring AOP前置通知实例讲解与AOP详细解析
一.引出问题 有个接口TestServiceInter,有两个实现方法TestService和Test2Service.他们都有sayHello():我们的需求是在调用这两个方法之前,要先完成写日志的 ...
- Spring AOP(通知、连接点、切点、切面)
一.AOP术语 通知(Advice) 切面的工作被称为通知.通知定义了切面是什么以及何时使用.除了描述切面要完成的工作,通知还解决了何时执行这个工作的问题.5种通知类型: 前置通知(Before): ...
随机推荐
- 解决新电脑的系统安装问题:针对BIOS的UEFI模式
安装win7或win8系统时UEFI和Legacy模式的设置 新的的笔记本或台式机主板都开始支持UEFI模式,不过这种模式让很多打算给电脑换win7或win8的用户头疼不已,尤其是笔记本用户. ...
- redis's usage
author:headsen chen date:2017-12-07 16:33:40 notice:This article is created by headsen chen ,and n ...
- Linux增加LV(逻辑卷)容量
Linux增加LV(逻辑卷)容量 2017-09-29-17:34:13 个人原创博客,转载请注明出处. 查看逻辑卷的相关命令: lvs vgs 命令: [root@arch ~]# vgs VG # ...
- Unity的常用API
1.Event Function:事件函数 Reset() :被附加脚本时.在游戏物体的组件上按Reset时会触发该事件函数 Start() :在游戏初始化时会执行一次 Update() :每一帧 ...
- 常用到的html页面布局和组件: 自己用
1. 用div当作圆 <div style="border: 1px solid blue;height: 100px; width: 100px; border-radius: 20 ...
- 1833 深坑 TLE 求解
题目描述: 大家知道,给出正整数n,则1到n这n个数可以构成n!种排列,把这些排列按照从小到大的顺序(字典顺序)列出,如n=3时,列出1 2 3,1 3 2,2 1 3,2 3 1,3 1 2,3 2 ...
- jdk 环境配置踩坑
其实在网上已经有很多环境配置的介绍了.不过我还是想用切身经历告诉大家这里面可能遇到的坑. 首先,先给大家讲一下JAVA_HOME,path,CLASSPATH JAVA_HOME 指向的是JDK的安装 ...
- u3d材质Tiling和Offset意义以及TRANSFORM_TEX
1. TRANSFORM_TEX主要作用是拿顶点的uv去和材质球的tiling和offset作运算, 确保材质球里的缩放和偏移设置是正确的 下面这两个函数是等价的.o.uv = TRANSFORM ...
- 解决Hash碰撞冲突方法总结
Hash碰撞冲突 我们知道,对象Hash的前提是实现equals()和hashCode()两个方法,那么HashCode()的作用就是保证对象返回唯一hash值,但当两个对象计算值一样时,这就发生了碰 ...
- CountDownLatch 源码解析—— await()
上一篇文章说了一下CountDownLatch的使用方法.这篇文章就从源码层面说一下await() 的原理. 我们已经知道await 能够让当前线程处于阻塞状态,直到锁存器计数为零(或者线程中断). ...