AOP(面向切面编程)

英文名称:(Aspect Oriented Programming)

正常程序执行流程都是纵向执行流程

又叫面向切面编程,在原有纵向执行流程中添加横切面

  • 特点:
    • 不需要修改原有程序代码
    • 高扩展性
    • 原有功能相当于释放了部分逻辑.让职责更加明确.

面向切面编程是什么?

  • 在程序原有纵向执行流程中,针对某一个或某一些方法添加通知,形成横切面过程就叫做面向切面编程.

  • 常用概念

    • 原有功能: 切点,pointcut
    • 前置通知: 在切点之前执行的功能.beforeadvice
    • 后置通知: 在切点之后执行的功能,afteradvice
    • 如果切点执行过程中出现异常,会触发异常通知.throwsadvice
    • 所有功能总称叫做切面.
    • 织入: 把切面嵌入到原有功能的过程叫做织入
    • spring 提供了 2 种 AOP 实现方式
      • Schema-based
        • 每个通知都需要实现接口或类
        • 配置 spring 配置文件时在<-aop:config>配置
      • AspectJ
        • 每个通知不需要实现接口或类
        • 配置 spring 配置文件是在<-aop:config>的子标签<-aop:aspect>中配置

    Schema-based 实现AOP

    导入jar

  • 新建通知类

    • 新建前置通知类–实现MethodBeforeAdvice接口

      • method: 切点方法对象 Method 对象
      • objects: 切点方法参数
      • o:切点在哪个对象中
    • 新建后置通知类–实现AfterReturningAdvice接口

      • o:切点方法返回值
      • method:切点方法对象
      • objects:切点方法参数
      • o1:切点方法所在类的对象
    • 配置 spring 配置文件

      • 引入 aop 命名空间

      • 配置通知类的<-bean>

      • 配置切面

      • ‘*’ 通配符,匹配任意方法名,任意类名,任意一级包名

      • 如果希望匹配任意方法参数 (..)

    • 异常通知–实现throwsAdvice接口

      • 必须自己写方法,且必须叫 afterThrowing

      • 有两种参数方式 必须是 1 个或 4 个

      • 异常类型要与切点报的异常类型一致

      • 在 ApplicationContext.xml 配置

    • 环绕通知–实现 MethodInterceptor接口

      • 新建一个类实现 MethodInterceptor

      • 配置spring配置文件

Schema-based 实现AOP总结

新建一个通知,要创建一个类来实现相应通知的接口。

在spring配置文件中,首先要通过bean标签将通知类交给spring实例化。然后通过aop:config标签配置切面,在此标签下通过aop:pointcut配置切点,expression属性配置切点的具体所在位置。通过aop:advisor标签引入相应已经给spring实例类。

AspectJ方式 实现AOP

  • 新建类,不用实现

    • 类中方法名任意
  • 配置 spring 配置文件

    • <-aop:after/> 后置通知,是否出现异常都执行

    • <-aop:after-returing/> 后置通知,只有当切点正确执行时执行

    • <-aop:after/> 和 <-aop:after-returing/> 和<-aop:after-throwing/>执行顺序和配置顺序有关

    • execution() 括号不能扩上 args

    • 中间使用 and 不能使用&& 由 spring 把 and 解析成&&

    • args(名称) 名称自定义的.顺序和 demo1(参数,参数)对应

    • <-aop:before/> arg-names=” 名 称 ” 名 称 来 源 于expression=”” 中 args(),名称必须一样

      • args() 有几个参数,arg-names 里面必须有几个参数

      • arg-names=”” 里面名称必须和通知方法参数名对应

AspectJ方式实现AOP总结

使用AspectJ方式不需要实现通知接口,自定义通知方法。

在spring配置文件中首先通过bean标签将存在通知方法的的类交给spring管理实例化。在通过aop:config标签配置切面,在标签内使用aop:aspect标签声明使用的是AspectJ方式并通过ref引用含有通知方法的类。通过aop:pointcut配置切点expression属性配置切点的具体所在位置。通过aop:before标签声明前置通知,aop:after标签声明后置通知,aop:after-throwing声明异常通知,aop:around声明环绕通知。此类标签通过pointcut-ref引用切点,method引用具体方法,arg-names引用参数。

使用注解实现AOP(基于 Aspect)

  • spring 不会自动去寻找注解,必须告诉 spring 哪些包下的类中可能有注解
    • 引入 xmlns:context 和context:component-scan标签
  • @Component
    • 相当于
    • 如果括号里没有参数,默认实例化后id为把类名首字母变小写,相当于<-bean id=””/>
    • @Component(“自定义名称”)
  • 在 Demo 类中添加@Componet
    • 在方法上添加@Pointcut(“execution(* 包名+类名+方法名”) 定义切点
  • 在通知类中配置
    • @Component 类被 spring 管理
    • @Aspect 相当于<-aop:aspect/>表示通知方法在当前类中
  • spring配置文件中修改代理模式 默认为jdk模式

代理设计模式

设计模式:前人总结的一套解决特定问题的代码.

  • 代理设计模式优点:
    • 保护真实对象
    • 让真实对象职责更明确.
    • 扩展
  • 代理设计模式
    • 真实对象.(老总)
    • 代理对象(秘书)
    • 抽象对象(抽象功能),谈小目标

静态代理设计模式

  • 由代理对象代理所有真实对象的功能.
    • 自己编写代理类
    • 每个代理的功能需要单独编写
  • 静态代理设计模式的缺点:
    • 当代理功能比较多时,代理类中方法需要写很多.

动态代理

为了解决静态代理频繁编写代理功能缺点.

  • 分类:

    • JDK 提供的
    • cglib 动态代理
  • JDK 动态代理

  • 和 cglib 动态代理对比

    • 优点:jdk 自带,不需要额外导入 jar
  • 缺点:

    • 真实对象必须实现接口
    • 利用反射机制.效率不高.

使用 JDK 动态代理时可能出现下面异常

出现原因:希望把接口对象转换为具体真实对象

cglib 动态代理

  • cglib 优点:
    • 基于字节码,生成真实对象的子类.
    • 运行效率高于 JDK 动态代理.
    • 不需要实现接口
  • cglib 缺点:
    非 JDK 功能,需要额外导入 jar
  • 使用 springaop 时,只要出现 Proxy 和真实对象转换异常
    • 设置为 true 使用 cglib
    • 设置为 false 使用 jdk(默认值)
      1
      <aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy>