1、AOP中关键性概念 

连接点(Joinpoint):程序执行过程中明确的点,如方法的调用,或者异常的抛出

目标(Target):被通知(被代理)的对象
注1:完成具体的业务逻辑

通知(Advice):在某个特定的连接点上执行的动作,同时Advice也是程序代码的具体实现,例如一个实现日志记录的代码(通知有些书上也称为处理)
注2:完成切面编程

代理(Proxy):将通知应用到目标对象后创建的对象(代理=目标+通知)
例子:外科医生+护士
注3:只有代理对象才有AOP功能,而AOP的代码是写在通知的方法里面的

切入点(Pointcut):多个连接点的集合,定义了通知应该应用到那些连接点
(也将Pointcut理解成一个条件 ,此条件决定了容器在什么情况下将通知和目标组合成代理返回给外部程序)
 
适配器(Advisor):适配器=通知(Advice)+切入点(Pointcut)

看图便于理解:

2.、AOP的核心点(通知、实现接口与应用场景)

通知类型    实现接口                                               应用场景前置通知    实现org.springframework.aop.MethodBeforeAdvice接口     买书、评论前加系统日志后置通知    实现org.springframework.aop.AfterReturningAdvice接口   买书返利环绕通知    实现org.aopalliance.intercept.MethodInterceptor接口    类似拦截器,会包括切入点,目标类前后都会执行代码异常通知    实现org.springframework.aop.ThrowsAdvice接口           出现异常执行系统提示,然后进行处理。价格异常为例过滤通知(适配器)    实现org.springframework.aop.support.RegexpMethodPointcutAdvisor接口   处理买书返利的bug

一、准备工作及用到的工具类

接口类IBookBiz:

package com.lgs.aop.biz;public interface IBookBiz {// 购书public boolean buy(String userName, String bookName, Double price);// 发表书评public void comment(String userName, String comments);
}

接口类IBookBiz的实现类BookBizImpl:

package com.lgs.aop.biz;import com.lgs.aop.exception.PriceException;public class BookBizImpl implements IBookBiz {public BookBizImpl() {super();}//买书public boolean buy(String userName, String bookName, Double price) {// 通过控制台的输出方式模拟购书// 如果数据为负数,就会爆出异常if (null == price || price <= 0) {throw new PriceException("book price exception");}//谁买的书,花费多少System.out.println(userName + " buy " + bookName + ", spend " + price);return true;}//评论public void comment(String userName, String comments) {// 通过控制台的输出方式模拟发表书评System.out.println(userName + " say:" + comments);}}

异常通知所需的运行时异常PriceException类:

package com.lgs.aop.exception;public class PriceException extends RuntimeException {public PriceException() {super();}public PriceException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {super(message, cause, enableSuppression, writableStackTrace);}public PriceException(String message, Throwable cause) {super(message, cause);}public PriceException(String message) {super(message);}public PriceException(Throwable cause) {super(cause);}}

spring-context.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:aop="http://www.springframework.org/schema/aop"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd"><!-- 本文件中配置整个项目中包含的所有的JavaBean,目的在于spring项目的统一管理 --><!-- <bean name="userBiz1" class="com.lgs.ioc.biz.impl.UserBizImpl1"></bean> -->
<bean name="userBiz2" class="com.lgs.ioc.biz.impl.UserBizImpl1"></bean>
<bean name="userBiz1" class="com.lgs.ioc.biz.impl.UserBizImpl2"></bean><bean name="personAction" class="com.lgs.ioc.web.PersonAction"><property name="userBiz" ref="userBiz2"></property>
</bean><bean name="userAction1" class="com.lgs.ioc.web.UserAction1"><property name="userBiz" ref="userBiz1"></property>
</bean>
<bean name="userAction2" class="com.lgs.ioc.web.UserAction2"><property name="userBiz" ref="userBiz1"></property>
</bean>
<bean name="userAction3" class="com.lgs.ioc.web.UserAction3"><property name="userBiz" ref="userBiz1"></property>
</bean><bean name="paramAction" class="com.lgs.ioc.web.ParamAction">
<!--     <property name="name" value="鲁迅"></property><property name="age" value="34"></property><property name="hobby"><list><value>学医</value><value>白话文学</value><value>作家</value></list></property> --><constructor-arg name="name" value="武则天"></constructor-arg><constructor-arg name="age" value="22"></constructor-arg><constructor-arg name="hobby"><list><value>跳舞</value><value>唱歌</value><value>当皇帝</value></list></constructor-arg>
</bean><!-- aop --><!-- 目标 -->
<bean name="bookBiz" class="com.lgs.aop.biz.BookBizImpl"></bean>
<!-- 前置通知 -->
<bean name="myBefore" class="com.lgs.aop.advice.MyMethodBeforeAdvice"></bean>
<!-- 后置通知 -->
<bean name="myAfter" class="com.lgs.aop.advice.MyAfterReturningAdvice"></bean>
<!-- 环绕通知 -->
<bean name="myFilterAdvice" class="com.lgs.aop.advice.MyMethodInterceptor"></bean>
<!-- 异常通知 -->
<bean name="myExceptionAdvice" class="com.lgs.aop.advice.MyThrowsAdvice"></bean><!-- 过滤通知 -->
<!-- org.springframework.aop.support.RegexpMethodPointcutAdvisor 这个类是固定的   myAfter2:过滤的是后置通知 -->
<bean class="org.springframework.aop.support.RegexpMethodPointcutAdvisor" id="myAfter2"><!-- 过滤的哪个通知,选择过滤的是后置通知  --><property name="advice" ref="myAfter"></property><!-- .*buy:[.*]任意字符0~n个,以buy结尾的方法 --><property name="patterns"><list><!-- 过滤掉了buy方法 --><value>.*buy</value></list></property>
</bean><!-- 生成代理(目标对象+通知) -->
<!--  org.springframework.aop.framework.ProxyFactoryBean:代理工厂   proxyFactoryBean:代理对象--><bean class="org.springframework.aop.framework.ProxyFactoryBean"id="proxyFactoryBean"><property name="target" ref="bookBiz"></property><!-- 代理工厂生产的代理需要实现的接口列表 --><property name="proxyInterfaces"><list><value>com.lgs.aop.biz.IBookBiz</value></list></property><!-- 代理通知列表 --><property name="interceptorNames"><list><value>myBefore</value><!-- <value>myAfter</value> --><value>myAfter2</value><value>myFilterAdvice</value><value>myExceptionAdvice</value></list></property></bean></beans>

测试类AopTest.java:(几个通知案例测试类基本相同,有变动我会截图展示出来的)

package com.lgs.aop.test;import org.springframework.context.support.ClassPathXmlApplicationContext;import com.lgs.aop.biz.IBookBiz;public class AopTest {public static void main(String[] args) {
//      获取到spring-Context.xml配置文件ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("/spring-context.xml");
//      根据bean的id得到实现类
//      IBookBiz bookBiz = (IBookBiz) applicationContext.getBean("bookBiz");
//      调用前置通知IBookBiz bookBiz = (IBookBiz) applicationContext.getBean("proxyFactoryBean");
//      买书bookBiz.buy("迪迦", "《光的力量》", 33d);
//      评论bookBiz.comment("迪迦", "我的力量源泉");}
}

二、前置通知

前置通知MyMethodBeforeAdvice (要实现MethodBeforeAdvice接口):

package com.lgs.aop.advice;
import java.util.Arrays;
import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;
/*** 前置通知*/
public class MyMethodBeforeAdvice implements MethodBeforeAdvice {
/*** 实现接口,实现方法* target:目标对象* method:被触发目标对象的方法* args:目标对象的目标方法的携带的参数*/public void before(Method method, Object[] args, Object target) throws Throwable {String targetName = target.getClass().getName();String methodName = method.getName();String params = Arrays.toString(args);String msg = "【系统日志】:正在调用->"+targetName+"."+methodName+",携带的参数:"+params;System.out.println(msg);}
}

使用前置通知需先进行配置,和一些改动(配置和改动如下)spring-context.xml

运行结果:

暗暗

三、后置通知

后置通知MyAfterReturningAdvice (要实现AfterReturningAdvice接口):相比于前置多了一个参数,返回值

package com.lgs.aop.advice;
import java.lang.reflect.Method;
import java.util.Arrays;
import org.springframework.aop.AfterReturningAdvice;
/*** 后置通知*/
public class MyAfterReturningAdvice implements AfterReturningAdvice {public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {String targetName = target.getClass().getName();String methodName = method.getName();String params = Arrays.toString(args);String msg = "【返利通知:返利3元】:正在调用->" + targetName + "." + methodName + ",携带的参数:" + params + ";目标对象所调用的方法的返回值:"+ returnValue;System.out.println(msg);}
}

配置spring-context.xml

调用测试AopTest.java  运行结果如下

暗暗

四、环绕通知:包含前置+后置通知

环绕通知MythodInterceptor(要实现MethodInterceptor接口):

package com.lgs.aop.advice;
import java.lang.reflect.Method;
import java.util.Arrays;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
/*** 环绕通知 */
public class MyMethodInterceptor implements MethodInterceptor {public Object invoke(MethodInvocation invocation) throws Throwable {Object target = invocation.getThis();Method method = invocation.getMethod();Object[] args = invocation.getArguments();// a.jsp window.open(b.jsp)// b.jsp xxx->返回object->b.jsp window.close();window.getArguments;String targetName = target.getClass().getName();String methodName = method.getName();String params = Arrays.toString(args);String msg = "【环绕通知】:正在调用->" + targetName + "." + methodName + ",携带的参数:" + params;System.out.println(msg);//invocation可以执行被代理的目标对象的业务方法//过滤器    chain.dofilter:放行Object returnValue = invocation.proceed();String msg2 = "【环绕通知】:目标对象所调用的方法的返回值:" + returnValue;System.out.println(msg2);return returnValue;}
}

配置spring-context.xml

调用测试AopTest.java  运行结果如下

五、异常通知

假如出现异常,会直接终止程序,不会在进行数据回滚

异常通知MyThrowsAdvice(要实现ThrowsAdvice接口):(要么同时成功,要么同时失败)

package com.lgs.aop.advice;
import org.springframework.aop.ThrowsAdvice;
import com.lgs.aop.exception.PriceException;
/*** 异常通知*/
public class MyThrowsAdvice implements ThrowsAdvice {public void afterThrowing( PriceException ex ) {System.out.println("价格输入有误,购买失败,请重新输入!!!");}
}

配置spring-context.xml

 对测试类AopTest.java 进行修改,制造异常数据(-33d)

package com.lgs.aop.test;import org.springframework.context.support.ClassPathXmlApplicationContext;import com.lgs.aop.biz.IBookBiz;public class AopTest {public static void main(String[] args) {
//      获取到spring-Context.xml配置文件ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("/spring-context.xml");
//      根据bean的id得到实现类
//      IBookBiz bookBiz = (IBookBiz) applicationContext.getBean("bookBiz");
//      调用前置通知IBookBiz bookBiz = (IBookBiz) applicationContext.getBean("proxyFactoryBean");
//      买书bookBiz.buy("迪迦", "《光的力量》", -33d);
//      评论
//      bookBiz.comment("迪迦", "我的力量源泉");}
}

 运行结果如下(会有提示,出现解决方案)

六、过滤通知

过滤通知:并不是每个方法都需要通知,所有需要过滤一下

配置spring-context.xml(过滤通知替代后置通知) 

运行结果:

OK!到这就结束了  希望能帮到你!!! 

spring之aop(前置通知,后置通知,环绕通知,过滤通知,异常通知)相关推荐

  1. 攀登Spring珠穆朗玛峰:前置与后置处理器

    文章目录 Spring的前置与后置处理器 前提知识 前置与后置处理器定义 前置处理器:BeanFactoryPostProcessor `postProcessBeanFactory`调用 后置处理器 ...

  2. spring的几个通知(前置、后置、环绕、异常、最终)

    1.没有异常的 2.有异常的 1.被代理类接口Person.java 1 package com.xiaostudy; 2 3 /** 4 * @desc 被代理类接口 5 * 6 * @author ...

  3. 前置,后置,环绕,异常增强(示例)

    ----------------------------------基础架构: 前置增强 ------------------------------------代码演示: public interf ...

  4. PHP通过__call实现简单的AOP(主事务后的其他操作)比如前置通知,后置通知

    /*** person class*/ class Person {/*** person class -> function say*/public static function say($ ...

  5. [C++再学习系列] 前置++与后置++

    前置++: type operator++(); 后置++: const type operator++(int ); 为了编译器区分前置和后置++,C++规定后缀形式有一个int类型参数,当函数被调 ...

  6. JavaScript运算符:递增递减运算符前置和后置的区别

    从两段代码说起 var num1 = 2; var num2 = 20; var num3 = --num1 + num2; var num4 = num1 + num2; console.log(n ...

  7. # c++运算符重载之 前置++, 后置++, 负号运算符, 类型转换函数, 以及输入输出运算符...

    c++运算符重载之 前置++, 后置++, 负号运算符, 类型转换函数, 以及输入输出运算符 标签(空格分隔): c++ 前言 我在c++学习的过程中, 对这几个不太常见的运算符重载不太会写.出现了很 ...

  8. c语言前置函数,C语言高级编程-函数前置与后置调用

    / linux gcc下测试通过(有Bug请提交) 使用本代码需要注名作者: fqheda 本代码遵循GPL V3.0标准,可免费使用-- 函数前置与后置调用 注解:在同一个.c中,一个函数A调用另一 ...

  9. (转)前置++和后置++的区别

    今天在阅读<google c++ 编程风格>的文档的时候,5.10. 前置自增和自减:有一句话引起了我的注意: 对于迭代器和其他模板对象使用前缀形式 (++i) 的自增, 自减运算符.,理 ...

  10. 前置++与后置++之一道简单的题目引发的思考

    引言 昨晚一时兴起,我脑子就问自己下面的代码会输出什么,也不知道我脑子为什么有这个代码模型,只是模糊的有些印象: #include <stdio.h> #include <stdli ...

最新文章

  1. 因为我说:volatile 是轻量级的 synchronized,面试官让我回去等通知!
  2. 【 FPGA 】控制数码管动态扫描显示的小实验
  3. 什么是ERP (转载自百度知道)
  4. VS为VC++添加UAC控制(VC程序默认管理员运行)
  5. PPT(五)-让你的图片靓起来!
  6. Canny边缘检测算法
  7. JAVA项目答辩的自我评价_毕业答辩的英文自我评价范文
  8. Interesting Array CodeForces - 483D(思维+线段树)
  9. C#让TopMost窗体弹出并置顶层但不获取当前输入焦点的终极办法
  10. Java程序Date类型比较
  11. set UVA 11136 Hoax or what
  12. [Flex]Flex编程注意之自动获取焦点、监听全局键盘事件
  13. 搭建Yum服务器及编译安装Httpd实验
  14. 游戏环境检测工具_自带基准测试的游戏大作盘点
  15. 研磨设计模式学习笔记1--简单工厂(SimpleFactory)
  16. 软件设计文档编写概述
  17. 电商系统商品库的基本功能设计与实现
  18. 编译原理NFA确定化
  19. 计算机综合应用技能,系统测评计算机综合应用技能期末作业题稿.doc
  20. 关于ios 卡顿检测分析

热门文章

  1. OpenCV入门笔记-更新篇
  2. Allegro不规则带通孔焊盘的制作
  3. 全国城市空气质量实时发布平台数据抓取采集获取
  4. 水星路由器wan口ip显示0_路由器wan口ip地址显示0.0.0.0怎么办(2)
  5. Linux系统如何分区
  6. python实现大规模邻域搜索(LNS)求解旅行商问题(TSP)
  7. 微信小程序数据数据绑定显示NaN
  8. 绝地求生更新维护限时领取星魂套装
  9. 很多人问如何把网页封装成app呢?
  10. 对开源软件的认识与实践-刘彬