自学内容网 自学内容网

Spring-AOP

目录

什么是AOP

AOP的实现方式

静态代理

动态代理

不使用匿名内部类

使用匿名内部类

两种动态代理

AOP相关术语

切点表达式

复用

JoinPoint

开启AOP功能

快速入门

接口

通知类型

切面优先级

后置通知中获取结果

异常通知中获取异常

基于XML配置AOP 


什么是AOP

面向切面编程,将交叉业务封装成切面,跟核心业务分离,减少重复代码和降低模块之间的耦合度交叉业务:与核心业务无关,但所有业务模块都会调用的公共逻辑

AOP的实现方式

静态代理

实现类实现这个接口,这个实现类的实例就是代理类的属性

代理类在编译阶段生成,在编译阶段将通知织入Java字节码中,也称编译时增强。

AspectJ使用的是静态代理。

缺点:一个接口就要写一个代理类,会类爆炸

动态代理

代理类在程序运行时创建,动态生成class字节码,这个字节码就是代理类,不会生成新类

将目标对象作为代理对象的一个属性

不使用匿名内部类

需要实现InvocationHandler接口 

使用匿名内部类

两种动态代理

jdk的Proxy

面向接口,只能增强实现类中接口中存在的方法,得到的对象是JDK代理对象的实例
生成的代理对象只能转换成接口不能转换成被代理类

JDK动态代理的核心是InvocationHandler接口和Proxy类。

缺点:目标类必须有实现的接口。如果某个类没有实现接口,那么这个类就不能用JDK动态代理。

Spring的CGlib

面向父类,可以增强父类的所有方法,得到的对象是被代理对象的子类

优点:目标类不需要实现特定的接口,更加灵活。

什么时候采用哪种动态代理?

  1. 如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP
  2. 如果目标对象实现了接口,可以强制使用CGLIB实现AOP
  3. 如果目标对象没有实现了接口,必须采用CGLIB库

两者的区别

  • jdk动态代理使用jdk中的类Proxy来创建代理对象,它使用反射技术来实现,不需要导入其他依赖。cglib需要引入相关依赖:asm.jar,它使用字节码增强技术来实现。

  • 当目标类实现了接口的时候Spring Aop默认使用jdk动态代理方式来增强方法,没有实现接口的时候使用cglib动态代理方式增强方法。

AOP相关术语

切点表达式

切点表达式用来定义通知(Advice)往哪些方法上切入
切点表达式可以指向类的方法,也可以指向接口的方法,也可以对没有实现接口的类进行切入

execution([访问控制权限修饰符] 返回值类型 [全限定类名]方法名(形式参数列表) [异常])

访问控制权限修饰符:

  • 可选项。
  • 没写,就是4个权限都包括。
  • 写public就表示只包括公开的方法。

返回值类型:

  • 必填项。
  • * 表示返回值类型任意。

全限定类名:

  • 可选项。
  • 两个点“..”代表当前包以及子包下的所有类。
  • 省略时表示所有的类。

方法名:

  • 必填项。
  • *表示所有方法。
  • set*表示以set开始的所有方法 。

形式参数列表:

  • 必填项
  • () 表示没有参数的方法
  • (..) 参数类型和个数随意的方法
  • (*) 只有一个参数的方法
  • (*, String) 第一个参数类型随意,第二个参数是String的。

异常:

  • 可选项。
  • 省略时表示任意异常类型。

复用

    //定义一个切入点, 在后面使用时可以直接引用, 提高了复用性
    @Pointcut(value = "execution(public float spring.aspectj.SmartDog.getSum(float, float)))")
    public void myPointCut() {}

    @Before(value = "myPointCut()")
    public void showBeginLog(JoinPoint joinPoint) {}

    @AfterReturning(value = "myPointCut()", returning = "res")
    public void showSuccessEndLog(JoinPoint joinPoint, Object res) {}

    @AfterThrowing(value = "myPointCut()", throwing = "throwable")
    public void showExceptionLog(JoinPoint joinPoint, Throwable throwable) {}

JoinPoint

JoinPoint joinPoint在底层执行时,由 AspectJ 切面框架给该切入方法传入 joinPoint对象

joinPoint.getSignature()获取方法签名

 

开启AOP功能

开启基于注解的AOP功能,spring容器在扫描类的时候,查看该类上是否有@Aspect注解,如果有,则给这个类生成代理对象

如果不开启,.getClass()不会得到代理对象,只会得到当前运行的对象(相当于new)


proxy-target-class,ture表示强制使用CGLIB动态代理,默认false,使用JDK动态代理

使用注解配置类

快速入门

接口

通知类型

确保环绕通知中的返回值与目标方法的返回类型匹配

环绕通知可以完成其他四个通知的功能

 

环绕是最大的通知,发生异常不会有后置通知和后环绕 

切面优先级

如果同一个方法,有多个切面在同一个切入点切入,优先级如何控制

注解@Order(value = n) 来控制,n 越小,优先级越高

前置通知通过@Order来判断顺序

后置通知中获取结果

在@AfterReturning 增加属性 , 比如 returning = "res",同时在切入方法增加 Object res
注意: returning = "res" 和 Object res 的 res名字一致

异常通知中获取异常

基于XML配置AOP 

接口、实现类、切面类(注解全部去掉)

<?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:context="http://www.springframework.org/schema/context"
       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/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">

    <!--使用XML配置,完成AOP编程-->
    <!--配置一个切面类对象-bean-->
    <bean class="com.hspedu.spring.aop.xml.SmartAnimalAspect" id="smartAnimalAspect"/>
    <!--配置一个SmartDog对象-bean-->
    <bean class="com.hspedu.spring.aop.xml.SmartDog" id="smartDog"/>
    <!--配置切面类, 细节一定要引入 xmlns:aop-->
    <aop:config>
        <!--配置切入点-->
        <aop:pointcut id="myPointCut" expression="execution(public float com.hspedu.spring.aop.xml.SmartDog.getSum(float, float)))"/>
        <!--配置切面的前置,返回, 异常, 最终通知-->
        <aop:aspect ref="smartAnimalAspect" order="10">
            <!--配置前置通知-->
            <aop:before method="showBeginLog" pointcut-ref="myPointCut"/>
            <!--返回通知-->
            <aop:after-returning method="showSuccessEndLog" pointcut-ref="myPointCut" returning="res"/>
            <!--异常通知-->
            <aop:after-throwing method="showExceptionLog" pointcut-ref="myPointCut" throwing="throwable"/>
            <!--最终通知-->
            <aop:after method="showFinallyEndLog" pointcut-ref="myPointCut"/>
            <!--配置环绕通知-->
            <!--<aop:around method=""/>-->
        </aop:aspect>
    </aop:config>
</beans>


原文地址:https://blog.csdn.net/qq_65186476/article/details/144356750

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!