通知和顾问都是切面的实现形式,其中通知可以完成对目标对象方法简单的织入功能。

而顾问包装了通知,可以让我们对通知实现更加精细化的管理,让我们可以指定具体的切入点。

通知分为前置通知,环绕通知及后置通知。

前置通知:在目标方法执行之前执行,不改变方法的执行流程及执行结果,前置通知的实现类要实现“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之通知和顾问的更多相关文章

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

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

  2. Spring AOP 四大通知

    Spring AOP 四大通知 Spring 3.X 以前 1.前置通知,实现  MethodBeforeAdvice 接口,重写 public  void  before(Method  metho ...

  3. spring aop 环绕通知around和其他通知的区别

    前言: spring 的环绕通知和前置通知,后置通知有着很大的区别,主要有两个重要的区别: 1) 目标方法的调用由环绕通知决定,即你可以决定是否调用目标方法,而前置和后置通知   是不能决定的,他们只 ...

  4. spring aop环绕通知

    [Spring实战]—— 9 AOP环绕通知   假如有这么一个场景,需要统计某个方法执行的时间,如何做呢? 典型的会想到在方法执行前记录时间,方法执行后再次记录,得出运行的时间. 如果采用Sprin ...

  5. Spring AOP前置通知和后置通知

    Spring AOP AspectJ:Java社区里最完整最流行的AOP框架 在Spring2.0以上的版本中,可以使用基于AspectJ注解或基于XML配置的AOP 在Spring中启用Aspect ...

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

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

  7. spring7——AOP之通知和顾问

    通知和顾问都是切面的实现形式,其中通知可以完成对目标对象方法简单的织入功能. 而顾问包装了通知,可以让我们对通知实现更加精细化的管理,让我们可以指定具体的切入点. 通知分为前置通知,环绕通知及后置通知 ...

  8. [转载] spring aop 环绕通知around和其他通知的区别

    前言: spring 的环绕通知和前置通知,后置通知有着很大的区别,主要有两个重要的区别: 1) 目标方法的调用由环绕通知决定,即你可以决定是否调用目标方法,而前置和后置通知   是不能决定的,他们只 ...

  9. Spring AOP前置通知实例说明AOP相关概念

    今天又看了下韩顺平的SpringAOP的讲解,讲解的很透彻.仿照视频自己使用下前置通知. 一.引出问题 有个接口TestServiceInter,有两个实现方法TestService和Test2Ser ...

  10. Spring AOP前置通知实例讲解与AOP详细解析

    一.引出问题 有个接口TestServiceInter,有两个实现方法TestService和Test2Service.他们都有sayHello():我们的需求是在调用这两个方法之前,要先完成写日志的 ...

随机推荐

  1. asp.net button控件 使用JS的 disabled

     今天想用JS禁用asp.net的button控件,查了好久,都是一行代码....      document.getElementById("Button1").disabled ...

  2. python爬虫挂代理

    以下是GET的方法,使用的代理接口网站是 http://www.xicidaili.com/nn/ #-*- coding:utf-8 -*- from bs4 import BeautifulSou ...

  3. SLEUTH 城市扩张模型

    3.19号准备试着运行一下SLEUTH模型,但是好不容易没报错出了一个test的结果,我就再也没看过了,导致现在我竟然差不多忘记当时怎么搞出来的了... 这也提醒我了,,,以后解决一个什么东西一定要立 ...

  4. Front-end: Using blurred backgrounds with contents unaffected.

    Purpose: Using a picture as the background of a page with blurred effect, while the content not blur ...

  5. File类相关操作

    1.File类常见方法: 创建: boolean createNewFile():在指定位置创建文件 如果该文件已经存在,则不创建,返回false,和输出流不一样,输出流对象一建立就创立文件,而且文件 ...

  6. javascript页面常用事件

    事件名称 描述 onload和 onunload(已过时) 当用户进入或离开页面时就会触发onload和onunload事件,onload是页面所有元素都加载完之后才加载onload onfocus, ...

  7. ios-项目启动页面

    项目运行启动页面: 点工程项目targets-(或Images.xcasets)-LaunchImage(iphone四种规格图片:320*480/350*568/640*960/640*1136)将 ...

  8. PythonStudy——三元表达式 Ternary expression

    Python中的三目运算其实就是if...else...的语法糖 # 三目运算符:用于简化 if...else...的语法结构# -- 1) 只能解决if...else...结构,其他if分支结构都不 ...

  9. 什么是pytorch(2Autograd:自动求导)(翻译)

    Autograd: 自动求导 pyTorch里神经网络能够训练就是靠autograd包.我们来看下这个包,然后我们使用它来训练我们的第一个神经网络. autograd 包提供了对张量的所有运算自动求导 ...

  10. phpmyadmin nginx设置

    1,解压缩phpmyadmin4.2.8压缩包到/usr/local/phpMyAdmin 2,复制config.sample.inc.php为config.inc.php 3,修改nginx.con ...