一、基础概念
AOP 是 Aspect-Oriented programming 的缩写,中文翻译为面向切面编程,它和 OOP 一样是一种编程思想。
OOP的优点:设计低耦合系统,但增加了代码的重复性,例如,想打印方法的出入日志,就需要在每个方法加上重复的代码,这时候就需要AOP编程思想。
AOP把系统分为核心关注点和横切关注点,核心关注点只需要负责业务的核心流程,横切关注点与核心业务关系不大,可以抽象出来的公共方法组件,像打印方法的出入日志、对方法加分布式锁、统计接口rt等。如下图所示:
AOP核心关注点和横切关注点.png
二、术语
术语 | 术语 | 说明 |
---|---|---|
连接点 | join point | 连接点指切面可以织入的一个点,这个点可以是调用方法时,抛出异常时、修改字段时,它是一个抽象的概念,在实现AOP时,不需要定义一个连接点 |
切入点 | point cut | 是指切面具体织入的位置,并不是所有的连接点都需要被织入,切入点时开发者自己选择连接点的方法 |
通知 | advice | 通知是切面的一种实现,可以完成简单织入功能。通知定义了增强代码切入到目标代码的时间点,是目标方法执行之前执行,还是之后执行等。通知类型不同,切入时间不同。 |
切面 | aspect | 切面泛指交叉业务逻辑,是切入点和通知的结合。比如事物处理,日志处理就可以理解为切面。实际就是对主业务逻辑的一种增强 |
织入 | weaving | 是指将切面应用到目标对象(新创建的代理对象)的过程。织入的方式包含:编译期织入、类加载期织入、运行期织入, |
织入: Spring 是通过何种方式将通知织入到目标方法上的。是通过实现后置处理BeanPostProcessor 接口。该接口是 Spring 提供的一个拓展接口,通过实现该接口,用户可在 bean 初始化完成后,即 bean 执行完初始化方法(init-method)。Spring通过切点对 bean 类中的方法进行匹配。若匹配成功,则会为该 bean 生成代理对象,并将代理对象返回给容器。容器向后置处理器输入 bean 对象,得到 bean 对象的代理,这样就完成了织入过程。
AOP术语如图所示:
AOP术语.png
通知类型:
术语 | 术语 | 说明 |
---|---|---|
前置通知 | @Before | 在执行目标方法之前运行 |
后置通知 | @After | 在目标方法运行结束之后,不管有没有异常 |
返回通知 | @AfterReturning | 在目标方法正常返回值后运行 |
异常通知 | @AfterThrowing | 在目标方法出现异常后运行 |
环绕通知 | @Around | 目标方法的调用由环绕通知决定,即你可以决定是否调用目标方法,joinPoint.procced()就是执行目标方法的代码 ,环绕通知可以控制返回对象 |
三、AOP实现原理
AOP 是基于 代理模式 和 装饰者模式 实现的。
代理模式和装饰者模式都是常用的 Java 设计模式,它的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务。
两种模式最主要的区别是:代理模式中,代理类对被代理的对象有控制权,决定其执行或者不执行。而装饰模式中,装饰类对代理对象没有控制权,只能为其增加一层装饰,以加强被装饰对象的功能。
代理类可以分为两种。
- 静态代理:由程序员或特定工具自动生成源代码,再对其编译。在程序运行前,代理类的 .class字节码 文件就已经存在。
- 动态代理:在程序运行时,工具类会动态的生成代理类的 .class字节码 缓存在内存中,再运用反射机制,实例化出代理对象。动态代理有以下几种实现形式:JDK自带的动态代理(常用)、CGLIB(常用)、javaassist字节码操作库实现、ASM(底层使用指令,可维护性较差)。
四、AOP 的具体实现
切面织入的方式有3种,分别是:
- 运行时织入(Runtime wearing):是指采用 jdk代理 或 cglib 工具进行切面的织入。
- 编译期织入(Compile time wearing):是指在 Java 编译期,采用特殊的编译器,将切面织入到 Java 类中。
- 类加载期织入(Classload time wearing):是指通过特殊的类加载器,在类字节码加载到 JVM 时织入切面。
Spring AOP 是采用运行时织入(Runtime wearing),它是基于动态代理的实现的。如果需要代理的对象,实现了某个接口,那么 Spring AOP 会使用 jdk代理 去创建代理对象,而对于没有实现接口的对象,Spring AOP 会使用 cglib 生成一个被代理对象的子类。
AspectJ 采用编译期织入(Compile time wearing)和类加载期织入(Classload time wearing),它是基于静态代理的实现的。
网友评论