AOP(面向切面编程)

英文名称:(Aspect Oriented Programming)

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

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

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

面向切面编程是什么?

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

  • 常用概念

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

1)目标方法的调用由环绕通知决定,即你可以决定是否调用目标方法,而前置和后置通知 是不能决定的,他们只是在方法的调用前后执行通知而已,即目标方法肯定是要执行的。

2) 环绕通知可以控制返回对象,即你可以返回一个与目标对象完全不同的返回值,虽然这很危险,但是你却可以办到。而后置方法是无法办到的,因为他是在目标方法返回值后调用

Schema-based 实现AOP

导入jar

前置通知

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

  • method: 切点方法对象 Method 对象
  • objects: 切点方法参数
  • o:切点在哪个对象中

后置通知

1.新建后置通知类–实现AfterReturningAdvice接口

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

2.配置 spring 配置文件

  • 引入 aop 命名空间
  • 配置通知类的<-bean>
  • 配置切面
  • ‘*’通配符,匹配任意方法名,任意类名,任意一级包名
  • 如果希望匹配任意方法参数 (..)

3.测试

异常通知

1.异常通知–实现ThrowsAdvice接口

  • 必须自己写方法,且必须叫afterThrowing
  • 有两种参数方式 必须是 1 个或 4 个
  • 异常类型要与切点报的异常类型一致

2.在 ApplicationContext.xml 配置

3.测试

环绕通知

1.环绕通知–实现MethodInterceptor接口

新建一个类实现 MethodInterceptor

2.配置spring配置文件

3.测试

总结

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

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

AspectJ方式实现AOP

xml

1.新建类,不用实现。类中方法名任意

2.配置 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方式不需要实现通知接口,自定义通知方法。

在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引用参数。

注解

spring 不会自动去寻找注解,必须告诉 spring 哪些包下的类中可能有注解,引入xmlns:context<context:component-scan>标签

@Component

  • 相当于<bean>
  • 如果括号里没有参数,默认实例化后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>