1.前言
前两篇博客介绍了一下,Spring中的IOC容器,这篇来讲解一下Spring中的AOP的知识。
2.AOP基础知识
2.1 概念
AOP是一种面向切面编程,一种软件工程的编程范式。AOP关注的是程序中的共性的功能,开发时,将共性功能抽取出来制作成独立的模块,此时原始代码中将不再具有这些被抽取出来的共性功能代码。因此加强了代码的复用性,同时程序开发时可以只考虑个性化功能,不需要考虑共性的功能。
2.2 基本知识点
连接点:具有特定功能的方法,一般方法
切入点:具有共性功能的方法的统称的一种称呼方式。
目标对象:包含切入点的类
通知:将共性功能抽取走,制作成独立的功能模块。
切面:切入点与通知匹配的一种情况。
AOP代理:运行过程中使用AOP创建代理对象进行运行,运行过程中将抽取的功能执行,该过程由AOP自动完成,所以称为AOP代理。
织入:将抽取的功能加入原始功能运行的整个过程叫做织入,织入控制的是字节码
工作流程
开发时,制作功能类(目标对象),将其中的方法中的通用功能(通知)抽取出来,制作成独立的类(通知类),原始目标对象中的方法(切入点)不再进行通用功能的制作。该功能被抽取后,无法完成完整的业务逻辑,需要在运行时将通知加入到对应的位置执行。为了完成此操作,必须将切入点与通知类进行一对一的对应关系设定(切面)
运行过程
运行时,Spring一直监控切面中所配置的切入点对应的方法的执行,发现执行了该方法,使用AOP的代理机制,创建代理对象(AOP代理),将原始方法(切入点)与通知进行融合,形成一个完成的业务逻辑进行运行,此过程称为织入。
3.AOP实践
3.1 简单的Demo
制作目标对象
<span style="font-family:SimSun;font-size:18px;"><span style="font-family:SimSun;font-size:18px;">//目标对象类 public class UserService { //连接点//切入点 public void add(){ //共性功能被抽取走了,放入到了MyAdvice类中的fn方法里 System.out.println("add"); } //连接点 public void delete(){ System.out.println("bbbbbb"); System.out.println("delete"); } } </span></span>制作通知
<span style="font-family:SimSun;font-size:18px;"><span style="font-family:SimSun;font-size:18px;">//通知类 public class MyAdvice { //具有共性功能的方法:通知 public void fn(){ //共性功能 System.out.println("aaaaa"); } } </span></span>AOPXML配置
<span style="font-family:SimSun;font-size:18px;"><span style="font-family:SimSun;font-size:18px;"><?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" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd "> <!-- 配置通知类为Bean --> <bean id="myAdvice" class="com.aop.MyAdvice"> </bean> <bean id="UserService" class="com.aop.UserService"> </bean> <!-- 配置AOP --> <aop:config> <!-- 配置切面 ref对应的通知类的beanID --> <aop:aspect ref="myAdvice"> <!-- 配置通知类与关系(切入点与通知方法) --> <!-- <aop:before method="fn" pointcut="execution(public void com.aop.UserService.add())" /> --> <!-- 不限定修饰符 --> <!-- <aop:before method="fn" pointcut="execution( void com.aop.UserService.add())" /> --> <!-- 不限定返回值 --> <!-- <aop:before method="fn" pointcut="execution( * com.aop.UserService.add())" /> --> <!-- <aop:before method="fn" pointcut="execution( * *.aop.UserService.add())" /> --> <!-- <aop:before method="fn" pointcut="execution( * com.*.UserService.add())" /> --> <!-- <aop:before method="fn" pointcut="execution( * *..*.UserService.add())" /> --> <!-- <aop:before method="fn" pointcut="execution( * *..UserService.add())" /> --> <!-- <aop:before method="fn" pointcut="execution( * *..*Service.add())" /> --> <!-- <aop:before method="fn" pointcut="execution( * *..User*.add())" /> --> <!-- <aop:before method="fn" pointcut="execution( * *..*.*())" /> --> <!-- 匹配一个参数 --> <!-- <aop:before method="fn" pointcut="execution( * *..*.*(*))" /> --> <!-- 匹配两个任意参数 --> <!-- <aop:before method="fn" pointcut="execution( * *..*.*(*,*))" /> --> <!-- 匹配任意参数 --> <!-- <aop:before method="fn" pointcut="execution( * *..*.*(..))" /> --> <!-- 匹配至少一个参数 --> <!-- <aop:before method="fn" pointcut="execution( * *..*.*(*,..))" /> --> <!-- 匹配第一个参数是int,后面无所谓 --> <!-- <aop:before method="fn" pointcut="execution( * *..*.*(int,..))" /> --> <aop:around method="fn" pointcut="execution( * *..*.*(..))"/> </aop:aspect> </aop:config> </beans> </span></span>注意:pointcut配置的是切入点表达式,pointcut-ref配置的是切入点引用对象,method配置的切入点执行的通知方法。
3.2 通知类别
before:前置通知(应用:各种校验)
在方法执行前执行,如果其中抛出异常
after:后通知(应用:清理现场)
方法执行完毕后执行,无论方法中是否出现异常
afterReturning:返回后通知(应用:常规数据处理)
方法正常返回后执行,如果方法中抛出异常,无法执行
afterThrowing:抛出异常后通知(应用:包装异常信息)
方法抛出异常后执行,如果方法没有抛出异常,无法执行
around:环绕通知(应用:十分强大,可以做任何事情)
方法执行前后分别执行,可以阻止方法的执行
//环绕通知 public void around(ProceedingJoinPoint pjp) throws Throwable{ System.out.println("around before......"); //调用原始方法 pjp.proceed(); System.out.println("around after......"); }1.通知的配置格式
<aop:before pointcut-ref="pt2" method="before"/> <aop:after pointcut-ref="pt2" method="after"/> <aop:after-returning pointcut-ref="pt2" method="afterReturning"/> <aop:after-throwing pointcut-ref="pt2" method="afterThrowing"/> <aop:around pointcut-ref="pt2" method="around"/>2.通知顺序:与配置顺序有关
多个切面间
先声明的before先运行,
后声明的before后运行
先声明的after后运行
后声明的after先运行
总结:配置时以最终运行顺序为准
版权声明:本文为博主原创文章,未经博主允许不得转载。