共计 4651 个字符,预计需要花费 12 分钟才能阅读完成。
读不在三更五鼓,功只怕一曝十寒。—— 郭沫若
@[toc]
一、导言
随着软件世界一直复杂化,传统的 OOP(面向对象)建模思路曾经不足以很好的解决好开发时所面临的种种挑战,AOP(Aspect Orient Programming)应运而生,它和 OOP 建模形式并不抵触,它是 OOP 编程的一种无效补充。
OOP 面向名词领域建模,应用类作为单位来模块化指标零碎,而 AOP 面向动词领域建模,其模块化单位则是Aspect
: 切面。
常见于解决一些具备 == 横切性质 == 的零碎级服务,例如: 日志治理、事务管理、安全检查缓存、对象池治理等
。
本文首先介绍了 AOP 次要概念和常见实现原理,后就动静代理引入 SpringAOP,并简略介绍了 SpringAOP 的原理和其反对的切面,最初做了一个总结。
二、AOP
2.1. 代理模式
说到 AOP 不得不说说 代理模式
。代理模式顾名思义,不间接拜访指标对象,而是通过一个代理对象来间接拜访指标对象。客户端代码隔着一层代理对象拜访指标对象,代理对象能够对拜访过程做各种加工、管制。如下类图简洁明了的展现了代理模式的依赖关系、类构造。
ProxyPatternDemo 类是客户端代码,Image 是形象接口,代理类 ProxyImage 和指标类 ReadlImage 都实现 Image,客户端代码通过代理对象能力拜访指标对象。
<img src=”https://www.runoob.com/wp-content/uploads/2014/08/20201015-proxy.svg” style=”zoom:70%;” />
2.2. AOP 外围概念
常见的 AOP 框架都应用代理的形式给 JointPoint~ 上面会介绍~ 增加“行为加强”,例如日志加强、事务加强等,具体能够了解为应用代理模式 == 通明的 == 的封装了客户端代码对被代理对象的拜访。
2.2.1. Aspect 切面
Aspect 对标 OOP 中的 class 的含意,封装 == 横切点的逻辑 == 和横切点逻辑的 == 作用范畴 ==。切面由切入点和告诉组成,它既蕴含了横切逻辑的定义,也包含了切入点的定义。具体的 日志、事务、线程池治理
等逻辑都在横切逻辑的Advice
(告诉)~ 上面有介绍~ 里实现。
2.2.1.1. PointCut 切入点
PointCut
是用于 == 限定横切逻辑作用范畴 == 的谓词限定式,其外围是 切点表达式
。由“切点表达式匹配JointPpoint
”的概念是 AOP 的外围,SpringAOP 默认应用 AspectJ 切点表达式语言,在理论应用上有以下两种模式,前者能够将切入点表达式形象进去,在 SpringAOP 中就是形象成一个办法:
- 应用
@PointCut
注解申明。 - 间接在 Advice 办法的注解里申明。
2.2.1.2. Advice 告诉
Advice 封装具体的横切逻辑。不同的横切逻辑能够以 around、before、after、return、afterThrow
等模式体现。Spring AOP 以拦截器的形式实现,并保护了一个以连接点~jointPoint~ 为核心的拦截器链。
2.2.2. JoinPoint 连接点
JoinPoint 是横切逻辑执行时所关联的点。在 JointPoint 的“前后左右等”方向上执行 Advice 逻辑。PointCut 表达式指定了 JointPoint 地位,Advice 的体现模式~after、before 等~ 指定了以什么模式在 JointPoint“左近”执行。
2.2.3. Introduction 引入
能够简略的了解为被代理对象增加办法或字段。
2.2.4. Targect Objecj 指标对象
被代理对象。被 AOP 框架解决的对象
2.2.5 Weaving 织入
织入是创立 Advice 代理对象并将 Aspect 代理对象和业务逻辑对象连接起来的过程。
织入能够在编译时,类加载时和运行时实现。在编译时进行织入就是动态代理,而在运行时进行织入则是动静代理。
2.3. 常见 AOP 实现原理
常见的 AOP 实现都是基于代理模式的,能够分为:1. 动态代理 2. 动静代理
两种。
动态代理 : 在 java 畛域中,最常见的基于动态代理的实现是AspectJ
(官网链接),目前曾经更新到AspectJ 9
了。AspectJ
反对编译时、编译后、类加载时织入。具体原理和应用办法暂且略过不表。
动静代理 : 动静代理能够分为基于JDK 动静代理
和CGLIB 动静代理
。都是在内存中长期为指标对象生成一个代理对象,客户端代码 == 通明的 == 通过调用代理对象提供的办法来拜访指标对象的办法。
而目前市面上最常见的基于 动静代理
的 AOP 实现是SpringAOP
。
三、SpringAOP
SpringAOP
是 Spring
框架的一个要害组件,其是基于 Spring IOC 容器而实现,与 IOC 容器无缝连接。SpringAOP 基于动静代理、纯 java 形式实现,不须要特定的编译过程,也不须要关怀 classLoader
类加载机制,实质上就是应用 JDK 动静代理或 CGLIB 来动静生成一个代理类。
3.1. SpringAOP 代理原理浅谈
当被代理对象有对应接口~ 所有的要被代理的办法在这个接口里都有申明~ 时,SpringAOP 应用 JDK 动静代理实现,当被代理对象没有对应的接口时,应用 CGLIB 实现。
CGLIB 能够了解为继承被代理类而动静产生一个代理对象,这和传统的代理模式有一点区别~ 传统代理模式有共有接口~。因为是应用继承机制来实现 AOP,所以 SpringAOP 不反对对 final
办法的代理,更不反对对 fianl
类的代理,因为子类无奈对父类办法进行override
(重写)。
3.2. SpringAOP 和 AspectJ
SpringAOP 目前只反对办法级别的 AOP 反对,我没有实现字段拦挡,如果须要对字段拜访进行 AOP 解决的话,能够思考应用 AspectJ 语言。
SpringAOP 不同于大多其余的 AOP 实现,SpringAOP 指标不是提供最残缺的 AOP 实现。它的亮点在于 AOP 和 SpringIOC 之间的紧密结合(尽管曾经很好用了),它非侵入的实现了 AOP,不依赖于 AspectJ 编译器和 AspectJ 织入器。在 SpringAOP 中应用一般的 bean 定义来定义 Aspect,SpringAOP 和 AspectJ 是互补的,不是非此即彼的。
下表是摘自这里的 SpringAOP 和 AspectJ 的要害区别:
Spring AOP | AspectJ |
---|---|
在纯 Java 中实现 | 应用 Java 编程语言的扩大实现 |
不须要独自的编译过程 | 除非设置 LTW,否则须要 AspectJ 编译器 (ajc) |
只能应用运行时织入 | 运行时织入不可用。反对编译时、编译后和加载时织入 |
性能不强 - 仅反对办法级编织 | 更弱小 – 能够编织字段、办法、构造函数、动态初始值设定项、最终类 / 办法等 ……。 |
只能在由 Spring 容器治理的 bean 上实现 | 能够在所有域对象上实现 |
仅反对办法执行切入点 | 反对所有切入点 |
代理是由指标对象创立的, 并且切面利用在这些代理上 | 在执行应用程序之前 (在运行时) 前, 各方面间接在代码中进行织入 |
比 AspectJ 慢多了 | 更好的性能 |
易于学习和利用 | 绝对于 Spring AOP 来说更简单 |
3.3. SpringAOP Advice
3.3.1. Before Advice : 前置告诉
在 JointPoint 前执行的 Advice,不可阻止 JointPoint 处办法的执行~Around 型能够~。应用 @Before
定义,具体源码如下所示。
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface Before {String value();
// 联合 SpringAOP 的命名绑定机制 (name binding) 应用,反对的 PCD 有: target、this、args
String argNames() default "";}
附: PCD(PointCut Designators 切点指示器),是切点表达式的重要组成部分。
3.3.2. After : 后置告诉
不论被代理办法是失常完结还是异样完结,都会执行这个 Advice。
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface After {String value();
// 同上
String argNames() default "";}
3.3.3. AfterReturning : 后置返回告诉
在 JointPoint 后执行的 Advice,当 JointPoint 处的办法失常执行完结后,会执行这个 Advice,如果是异样执行话则不会。应用 @AfterReturning
定义,具体源码如下所示。
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface AfterReturning {String value() default "";
// 和 value 同一个作用
String pointcut() default "";
// 用于申明返回值
String returning() default "";
// 同上
String argNames() default "";}
能够简略的看成带返回值的After
advice。
3.3.4. AfterThrowing : 后置异样告诉
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface AfterThrowing {String value() default "";
String pointcut() default "";
// 当 throwing 指定的异样产生时会调用这个 Advice
String throwing() default "";
// 同上
String argNames() default "";}
失常完结不会调用这个 Advice,当指定异样产生时会调用这个 Advice。
3.3.5. Around: 盘绕告诉
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface Around {String value();
// 同上
String argNames() default "";}
// 常和 ProceedingJoinPoint 类结伴应用
== 最弱小的 Advice==,简直所有的其余类型的 Advice 都能够应用盘绕告诉来实现。但 Spring 官网倡议选用“能实现所需行为的性能最小的告诉类型”: 提供最简略的编程模式,缩小了出错的可能性。
四、总结
一般来说,咱们能够通过手动编写的模式来实现代理模式,但当须要被代理的对象、类 == 有很多 == 时,手动编写的形式就不太适合,AOP 就是适宜这种有很多横切点的且横切点能够形象出对立逻辑的一种编程范型。
举一个在理论生产中很常见的例子:
如果某些业务逻辑接口的调用都须要在办法开始前和办法开始之后打日志,能够应用 AOP 切面的形式在所有的业务逻辑办法~JoinPoint~ 处定义两个 Advice: before 和 after 类型的。
五、参考链接
- 面试官:什么是 AOP?Spring AOP 和 AspectJ 的区别是什么?
- 代理模式
- 原生 AOP 用法剖析
- 了解 AOP 基本概念
- 代理模式是什么,SpringAOP 还和它有关系?
== 一键三连 == 反对下吧