Spring的AOP

作者: 善倾 | 来源:发表于2018-09-21 15:37 被阅读0次

    面向切面编程是对于面向对象的一种补充,是一种很先进的思想,技术实现倒不是很高深,关于 Spring 的 AOP 需要掌握的有以下这些。

    AOP 并不是 Spring 框架独有的,Spring 只是支持 AOP 编程的框架之一而已。不同的框架对 AOP 的支持各有特点,有些框架支持对方法及其参数做拦截,有些则只能对方法进行拦截。Spring 就是后者,它只支持对方法进行拦截的 AOP 。

    _Spring的AOP.png

    AOP概述

    AOP 全称是 Aspect Oriented Programming ,中文含义面向切面编程。

    AOP 的概念

    网上官方说法:

    Spring 的 AOP 指的就是在程序运行时,动态的将代码切入到指定位置上的一种编程思想。

    自己的理解:

    Spring 会通过配置文件是否进行了 AOP 相关的配置,来动态决定到底应该采用目标对象还是代理对象。代理对象是对原有目标对象的方法进行了增强,所以一旦采用了代理对象,就会出现和原有不一样的效果。

    为什么要使用AOP

    比如在 Spring 中,只要编写一个切面类,然后进行相关配置,Spring 就会去创建代理对象。如此就实现了在不修改原有代码的情况下,达到了和修改原有代码相同的效果。Spring 中的 AOP 通常都是用来进行权限校验、日志记录、性能监控、事务控制等功能的。

    AOP 的底层实现原理

    底层实现无非就是,在通过依赖注入给 Bean 对象的属性进行赋值的时候,根据配置来决定是注入原有目标对象还是代理对象。Spring 中生成代理对象使用的技术有两种,分别是 JDK 动态代理,和 CGLib 动态代理。

    JDK 动态代理

    要求目标类必须实现接口,才能采用这种方式产生代理对象。

    CGLib 动态代理

    针对没有实现接口的类产生代理,它是通过继承的方式实现的代理。

    AOP的相关术语

    下面以CustomerDao类为例,来讲解 AOP 相关术语。

    //目标类
    public class CustomerDao {
        public void save() {
            System.out.println("保存客户...");
        }
        public void find() {
            System.out.println("查询客户...");
        }
        public void update() {
            System.out.println("修改客户...");
        }
        public void delete() {织入
            System.out.println("删除客户...");
        }
    }
    
    //切面类,下面是两个方法就是通知
    public class MyAspectXML {
        public void checkPri(JoinPoint jointPoint) {
            System.out.println("权限校验 "+jointPoint);
        }
        public void writeLog(Object result) {
            System.out.println("日志记录 "+result);
        }
    }
    

    前面已经提到,Spring 支持的是基于方法的 AOP ,也就是说它只能对方法进行增强。


    _AOP相关术语.png

    相关术语:

    • 连接点(Joinpoint),目标类的所有方法,因为所有方法都可能被增强
    • 切入点(Pointcut),就是会被增强的方法
    • 通知(Advice),就是切面类中由程序员添加的用于在切入点之前或之后执行的方法,比如权限验证方法和日志记录方法。
    • 目标类(Target),就是原有目标类啊
    • 代理类(Proxy),由 Spring 框架集合目标类、切面类和配置文件生成的对切入点进行了增强的那个类
    • 切面(Aspect),切入点和通知的组合,就是一个切面。比如save()writeLog()两个方法就组成了一个切面。面向切面编程就是在原有的方法之前或之后添加方法,组成一个新的方法呗。
    • 织入(Weaving),就是把通知应用到切入点的这个过程就叫做织入。也就是生成代理对象的过程呗!

    通知的类型

    通知就是切面类中的一个个方法,通知的类型指的是它和切入点的组成关系。


    _通知的类型.png
    • 前置通知,在切入点之前执行的方法,比如权限验证方法。
    • 后置通知,在切入点之后执行的方法,比如日志记录方法。
    • 环绕通知,在切入点之后和之后都会执行的方法,比如记录当前时间的方法,通常用于测试系统性能。
    • 异常抛出通知,在切入点出现异常的时候会执行的方法,无非就是捕捉到异常后,先执行此方法,再抛出异常而已。
    • 最终通知,无论切入点是否出现异常,都会执行该方法,其实就是把通知加在了 finally代码块之内呗。

    切入点表达式的写法

    如何通过配置指定哪些类的哪些方法需要进行增强呢?就是通过切入点表达式来实现的。

    切入点表达式的格式是:方法返回值+包名.类名.方法名(方法的参数),其中除了参数之外,其他任何一个位置都可以用通配符*表示。方法的参数用..表示。

    实际使用范例如下:

    <aop:pointcut expression="execution(* packageName.ProductDaoImpl.save(..))" id="pointcut1"/>
    

    XML 配置AOP

    配置 AOP 首先要明确几个角色,分别是切面类,目标类,切入点、通知。以上面的目标类和切面类为例,他们的配置如下

    <aop:config>
        <!-- 配置切入点 -->
        <aop:pointcut expression="execution(* com.itheima.spring.demo3.ProductDaoImpl.save(..))" id="pointcut1"/>
        <aop:pointcut expression="execution(* com.itheima.spring.demo3.ProductDaoImpl.delete(..))" id="pointcut2"/>
        <aop:pointcut expression="execution(* com.itheima.spring.demo3.ProductDaoImpl.update(..))" id="pointcut3"/>
        <aop:pointcut expression="execution(* com.itheima.spring.demo3.ProductDaoImpl.find(..))" id="pointcut4"/>
        <!-- 配置切面类,此标签内可以配置多个切面 -->
        <aop:aspect ref="myAspect">
            <!-- 前置通知  -->
            <aop:before method="checkPri" pointcut-ref="pointcut1"/>
            <!-- 后置通知 -->
            <aop:after-returning method="writeLog" pointcut-ref="pointcut2" returning="result"/>
            <!-- 环绕通知 -->
            <aop:around method="around" pointcut-ref="pointcut3"/>
            <!-- 异常抛出通知 -->
            <aop:after-throwing method="afterThrowing" pointcut-ref="pointcut4" throwing="ex"/>
            <!-- 最终通知 -->
            <aop:after method="after" pointcut-ref="pointcut4"/>
        </aop:aspect>
    </aop:config>
    

    AspectJ注解配置AOP

    用 AspectJ 注解的方式配置 AOP ,其实主要是需要配置切面类和通知,还有切入点。

    切面类的配置:

    • @Aspect ,用此注解给切面类进行配置。
    @Aspect//表明是切面类
    public class MyAspectAnno {}
    

    通知的配置:

    • @Before,配置前置通知
    @Before(value="execution(* com.itheima.spring.demo1.OrderDao.save(..))")
    public void before() {
        System.out.println("save方法前置增强=====");
    }//其他通知同理
    
    • @AfterReturning,配置后置通知
    • @Around,环绕通知
    • @AfterThrowing,配置异常抛出通知
    • @After,配置最终通知

    切入点的配置:

    • @Pointcut
    @Pointcut(value="execution(* packageName.ProductDaoImpl.save(..))")
    public void save() {
        System.out.println("保存订单...");
    }
    

    相关文章

      网友评论

        本文标题:Spring的AOP

        本文链接:https://www.haomeiwen.com/subject/ruzanftx.html