Spring AOP基础

AOP

AOP相关概念

  • Joinpoint(连接点):就是方法

  • Pointcut(切入点):就是挖掉共性功能的方法

  • Advice(通知):就是共性功能,最终以一个方法的形式呈现

  • Aspect(切面):就是共性功能与挖的位置的对应关系

  • Target(目标对象):就是挖掉功能的方法对应的类产生的对象,这种对象是无法直接完成最终工作的

  • Weaving(织入):就是将挖掉的功能回填的动态过程

  • Proxy(代理):目标对象无法直接完成工作,需要对其进行功能回填,通过创建原始对象的代理对象实现

  • Introduction(引入/引介) :就是对原始对象无中生有的添加成员变量或成员方法

在这里插入图片描述
在这里插入图片描述

AOP开发过程

开发阶段

正常的制作程序

将非共性功能开发到对应的目标对象类中,并制作成切入点方法

将共性功能独立开发出来,制作成**通知**

在配置文件中,声明**切入点**

在配置文件中,声明切入点与通知间的关系(含通知类型),即切面

运行阶段(AOP完成)

Spring容器加载配置文件,监控所有配置的**切入点**方法的执行

当监控到**切入点**方法被运行,使用**代理**机制,动态创建**目标对象**的**代理对象**,根据**通知类别**,
在**代理对象**的对应位置将**通知**对应的功能**织入**,完成完整的代码逻辑并运行

AOP配置(XML)

常用注解

AspectJ

 Aspect(切面)用于描述切入点与通知间的关系,是AOP编程中的一个概念

 AspectJ是基于java语言对Aspect的实现

aop:config

类型:标签

归属:beans标签

作用:设置AOP

aop:aspect

类型:标签

归属:aop:config标签

作用:设置具体的AOP通知对应的切入点

说明:一个aop:config标签中可以配置多个aop:aspect标签

基本属性:
	 ref :通知所在的bean的id

aop:pointcut

 类型:**标签**

归属:aop:config标签、aop:aspect标签

作用:设置切入点
说明:
一个aop:config标签中可以配置多个aop:pointcut标签,且该标签可以配置在aop:aspect标签内

基本属性:
id :识别切入点的名称
expression :切入点表达式

切入点

  • 切入点描述的是某个方法

  • 切入点表达式是一个快速匹配方法描述的通配格式,类似于正则表达式

切入点表达式的组成

格式:关键字(访问修饰符  返回值  包名.类名.方法名(参数)异常名)

关键字:描述表达式的匹配模式(参看关键字列表)

​访问修饰符:方法的访问控制权限修饰符

​类名:方法所在的类(此处可以配置接口名称)

​异常:方法定义中指定抛出的异常

切入点表达式——关键字

  • execution :匹配执行指定方法

  • args :匹配带有指定参数类型的方法

  • within :……

  • this :……

  • target :……

  • @within :……

  • @target :……

  • @args :……

  • @annotation :……

  • bean :……

  • reference pointcut :……
    切入点表达式——通配符

  • *:单个独立的任意符号,可以独立出现,也可以作为前缀或者后缀的匹配符出现

    execution(public * com.itheima.*.UserService.find*(*))
    
    匹配com.itheima包下的任意包中的UserService类或接口中所有find开头的带有一个参数的方法
    
  • …:多个连续的任意符号,可以独立出现,常用于简化包名与参数的书写

    execution(public User com..UserService.findById(..))
    
    匹配com包下的任意包中的UserService类或接口中所有名称为findById的方法
    
  • +:专用于匹配子类类型

	execution(* *..*Service+.*(..))

切入点的三种配置方式

<aop:config>
    <!--配置公共切入点-->
    <aop:pointcut id="pt1" expression="execution(* *(..))"/>
    <aop:aspect ref="myAdvice">
        <!--配置局部切入点-->
        <aop:pointcut id="pt2" expression="execution(* *(..))"/>
        <!--引用公共切入点-->
        <aop:before method="logAdvice" pointcut-ref="pt1"/>
        <!--引用局部切入点-->
        <aop:before method="logAdvice" pointcut-ref="pt2"/>
        <!--直接配置切入点-->
        <aop:before method="logAdvice" pointcut="execution(* *(..))"/>
    </aop:aspect>
</aop:config>

通知类型
AOP的通知类型共5种

  • 前置通知:原始方法执行前执行,如果通知中抛出异常,阻止原始方法运行
  • 后置通知:原始方法执行后执行,无论原始方法中是否出现异常,都将执行通知
  • 返回后通知:原始方法正常执行完毕并返回结果后执行,如果原始方法中抛出异常,无法执行
  • 抛出异常后通知:原始方法抛出异常后执行,如果原始方法没有抛出异常,无法执行
  • 环绕通知:在原始方法执行前后均有对应执行执行,还可以阻止原始方法的执行

aop:before

类型:标签

归属:aop:aspect标签

作用:设置前置通知

说明:一个aop:aspect标签中可以配置多个aop:before标签

基本属性:

  method :在通知类中设置当前通知类别对应的方法
  pointcut :设置当前通知对应的切入点表达式,与pointcut-ref属性冲突
  pointcut-ref :设置当前通知对应的切入点id,与pointcut属性冲突
  <!--前置通知,调用连接点方法之前执行的通知-->
            <aop:before method="check"  pointcut-ref="pc"/>

aop:after

类型:标签

归属:aop:aspect标签

作用:设置后置通知
说明:一个aop:aspect标签中可以配置多个aop:after标签

基本属性:

  method :在通知类中设置当前通知类别对应的方法
  pointcut :设置当前通知对应的切入点表达式,与pointcut-ref属性冲突
  pointcut-ref :设置当前通知对应的切入点id,与pointcut属性冲突
<!--后置通知,调用连接点方法之后执行的通知-->
            <aop:after method="log"  pointcut-ref="pc"/>

aop:after-returning

类型:标签

归属:aop:aspect标签

作用:设置返回后通知
说明:一个aop:aspect标签中可以配置多个aop:after-returning标签
基本属性:

	method :在通知类中设置当前通知类别对应的方法

  	pointcut :设置当前通知对应的切入点表达式,与pointcut-ref属性冲突

  	pointcut-ref :设置当前通知对应的切入点id,与pointcut属性冲突
<aop:aspect ref="adviceId">
    <aop:after-returning method="methodName" pointcut="……"/>
</aop:aspect>

aop:after-throwing

类型:标签

归属:aop:aspect标签

作用:设置抛出异常后通知
说明:一个aop:aspect标签中可以配置多个aop:after-throwing标签
基本属性:

  method :在通知类中设置当前通知类别对应的方法

  pointcut :设置当前通知对应的切入点表达式,与pointcut-ref属性冲突

  pointcut-ref :设置当前通知对应的切入点id,与pointcut属性冲突
  <aop:aspect ref="adviceId">
    <aop:after-throwing method="methodName" pointcut="……"/>
</aop:aspect>

aop:around

类型:标签

归属:aop:aspect标签

作用:设置环绕通知
说明:一个aop:aspect标签中可以配置多个aop:around标签
基本属性:

  method :在通知类中设置当前通知类别对应的方法

  pointcut :设置当前通知对应的切入点表达式,与pointcut-ref属性冲突

  pointcut-ref :设置当前通知对应的切入点id,与pointcut属性冲突

环绕通知是在原始方法的前后添加功能,在环绕通知中,存在对原始方法的显式调用

<aop:aspect ref="adviceId">
    <aop:around method="methodName" pointcut="……"/>
</aop:aspect>
环绕通知方法相关说明:
	1、方法须设定Object类型的返回值,否则会拦截原始方法的返回。如果原始方法返回值类型为void,
	通知方	也可以设定返回值类型为void,最终返	回null
	2、 方法需在第一个参数位置设定ProceedingJoinPoint对象,通过该对象调用proceed()方法,实现对原始方法的调用。
	如省略该参数,原始方法将无法执行
	3、使用proceed()方法调用原始方法时,因无法预知原始方法运行过程中是否会出现异常,强制抛出Throwable对象,
	封装原始方法中可能出现的异常信息

通知获取数据

通知获取参数数据

  • 第一种情况:

    1、设定通知方法第一个参数为JoinPoint,通过该对象调用getArgs()方法,获取原始方法运行的参数数组
    2、所有的通知均可以获取参数
    
public void before(JoinPoint jp) throws Throwable {
    Object[] args = jp.getArgs();
}
  • 第二种情况:

     设定切入点表达式为通知方法传递参数(锁定通知变量名)
    

注意:args(x,y)位置跟切入方法的参数位置一样,但是当使用了arg-name属性x,y要对应

 <aop:before
                    method="before1"
                    arg-names="y,x"
                    pointcut="execution(* *..*(int,int)) &amp;&amp; args(x,y)"/>

        </aop:aspect>

通知获取返回值数据

  • 第一种:返回值变量名

    设定返回值变量名
    

原始方法:

public int save() {
		System.out.println("user service running...");
	    return 100;
	}

AOP配置:

<aop:aspect ref="myAdvice">
    <aop:pointcut id="pt3" expression="execution(* *(..))  "/>
    <aop:after-returning method="afterReturning" pointcut-ref="pt3" returning="ret"/>
</aop:aspect>

通知类:

public void afterReturning(Object ret) {
    System.out.println(ret);
}

适用于返回后通知(after-returning)

  • 第二种:
  • 在通知类的方法中调用原始方法获取返回值

  • 原始方法

    public int save() {
        System.out.println("user service running...");
        return 100;
    }
    
  • AOP配置l

    <aop:aspect ref="myAdvice">
        <aop:pointcut id="pt2" expression="execution(* *(..))  "/>
        <aop:around method="around" pointcut-ref="pt2" />
    </aop:aspect>
    
  • 通知类

    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        Object ret = pjp.proceed();
        return ret;
    }
    

适用于环绕通知(around)

AOP配置(注解)

注解开发AOP制作步骤

在XML格式基础上

1、导入坐标(伴随spring-context坐标导入已经依赖导入完成)

2、开启AOP注解支持

3、配置切面@Aspect

4、定义专用的切入点方法,并配置切入点@Pointcut

5、为通知方法配置通知类型及对应切入点@Before

注解开发AOP注意事项

1.切入点最终体现为一个方法,无参无返回值,无实际方法体内容,但不能是抽象方法

2.引用切入点时必须使用方法调用名称,方法后面的()不能省略

3.切面类中定义的切入点只能在当前类中使用,如果想引用其他类中定义的切入点使用“类名.方法名()”引用

4.可以在通知类型注解后添加参数,实现XML配置中的属性,例如after-returning后的returning属性

AOP注解详解

@Aspect

类型:注解

位置:类定义上方

作用:设置当前类为切面类

说明:一个beans标签中可以配置多个aop:config标签

@Pointcut

类型:注解

位置:方法定义上方

作用:使用当前方法名作为切入点引用名称

说明:被修饰的方法忽略其业务功能,格式设定为无参无返回值的方法,方法体内空实现(非抽象)

@Before

类型:注解

位置:方法定义上方

作用:标注当前方法作为前置通知

@After

类型:注解

位置:方法定义上方

作用:标注当前方法作为后置通知

@AfterReturning

类型:注解

位置:方法定义上方

作用:标注当前方法作为返回后通知

特殊参数:
	 returning :设定使用通知方法参数接收返回值的变量名

@AfterThrowing

类型:注解

位置:方法定义上方

作用:标注当前方法作为异常后通知

特殊参数:
	hrowing :设定使用通知方法参数接收原始方法中抛出的异常对象名

@Around

类型:注解

位置:方法定义上方

作用:标注当前方法作为环绕通知

@EnableAspectJAutoProxy

类型:注解

位置:Spring注解配置类定义上方

作用:设置当前类开启AOP注解驱动的支持,加载AOP注解
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值