2-面向切面编程
1. 软件编程方法
- 面向过程编程 POP
- 面向对象编程 OOP
- 面向切面编程 AOP
- 函数式编程 FP
- 反应式编程 RP
2. AOP: Aspect Oriented Programming
2.1. 👍横切关注点
2.1.1. 定义
- 横切关注点:公共性的功能,但需要嵌入到业务代码的许多地方
- Cross-cutting concern
- 例:来了一个请求,需要权限认证。权限认证与业务逻辑无关,且许多地方要用到。
Spring会帮开发者嵌入横切关注点
2.1.2. 类型
- 日志
- 安全
- 事务
- 缓存
2.2. AOP的可选方案
以日志为例
- 继承
- 让业务类继承日志类
- 缺点:感知到日志代码存在,强耦合,对业务代码造成了侵入
- 委托
- 委托日志对象的引用来调用日志方法
- 缺点:需要知道日志模块的存在,侵入业务代码
3. 👍AOP术语
- 通知 Advice:切面要做什么以及何时做
- 时间:方法前/后…
- 切点 Pointcut:指定在何处切
- Spring只支持在方法的前后切
- 写切点表达式指定逻辑
- 切面 Aspect:Advice和Pointcut的结合
- 包含切的所有逻辑
- 连接点 Join point:方法、字段修改、构造方法
- 引入 introduction:引入新的行为和状态
- 给对象加入新的方法/状态,但不需要实现新的子类。在原来的对象上动态加入新的方法/状态。
- 织入 Weaving:切面应用到目标对象的过程
3.1. 通知 Advice
在aspect类的方法上注解
- @Before
- @After:不区分是否正常结束
- @AfterReturning
- @AfterThrowing
- @Around:结合前面所有类型
被切方法成功运行之后会执行:After、AfterReturning、Around
3.2. 切点 Pointcut
@Pointcut
,空方法- 可以在不同的Advice的切点表达式中直接重用
- 消除重复
- 不是方法调用
- 相当于对比较复杂的切点表达式进行封装,简单的就可以直接写在Advice里
3.3. 👍切面 Aspect
- java类上加
@Aspect
注解,是一个单独的类- @Aspect // 并不具有 @Component 的效果,不能在扫描时实例化,因此需要添加 @Component 注解或在 JavaConfig 类中主动实例化
- 包含切的时间、切点和逻辑
- 定义可重用的切点
==不需要修改业务代码==
3.3.1. 创建步骤
- 实现一个java类,在类上加
@Aspect
注解,定义逻辑和行为。用@Before
等注解定义Advice和切点表达式。 - 在配置类增加注解
@EnableAspectJProxy
- 启用AspectJ代理
- 实例化:在配置类中实例化切面类对应的Bean,或者使用
@Component
3.3.2. 👍切点表达式/切点指示器
- 借助
AspectJ
切点指示器的语法 - 在方法上加
@Before(<expression>)
、@Pointercut(<expression)
- 可以实现👍
- 指定在哪些方法上切入
- 获取参数
- 限定包路径
- 限定bean名称,白名单或黑名单
- 限定在特定注解上切入
3.3.2.1. `Pointcut
1 |
|
- 指定方法
execution
- 可以指定包/路径
within
- 可以带参数
args
- 限定在哪些Bean上植入(可以取反)
bean
3.3.2.2. Around
@annotation
关键字指定在特定注解上植入- 注解可以自己定义,和Spring无关
Around
- 需要一个ProceedingJoinPoint方法参数
- 对ProceedingJoinPoint方法的调用实际上就是对切点的调用
1 | // |
- Around优势
- 可以自由控制是否调用/调用次数
- 可以有返回值,灵活性更高
3.3.3. 实现原理
- 切与不切通过
getBean
获得的对象类型并不一样。 - 通过创建代理实现
- JDK本身就具备代理能力
- 针对该对象的调用都会转到代理对象
3.4. 织入 Weaving
切面应用到目标对象的过程。
3.4.1. 织入时机
- 编译期: 需要特殊的编译器
- 类加载期: 需要类加载器的处理
- 运行期: Spring所采纳的方式,使用代理对象,只支持方法级别的连接点
3.4.2. 织入方式
使用代理机制。
3.5. 引入 👍introduction
引入新的行为和状态。
3.5.1. 引入方式
- 创建需要增加的接口和实现类
- 新建一个切面类,加
@Aspect
- 在里面定义一个新增实现类的
static
接口,加上@DeclareParents
注解 - 实例化切面类Bean
3.5.2. 例子
定义切面,为对象增加新的行为。Encoreable接口里包含要引入的新的行为的定义。新的行为引入到原有类中的时候,每个类都会实例化一个新的DefaultEncoreable类,一对一。
切面本身是单实例的,但是实现新行为的类对应的实例和被切入类是一对一的。
@DeclareParents
:value
:给实现了这个接口的对象,引入新的行为defaultImpl
:实现了需要引入的新行为。在该例子中实现了Encoreable
。
main
和测试
- 标题: 2-面向切面编程
- 作者: Charlie
- 创建于 : 2023-10-10 18:10:00
- 更新于 : 2024-07-05 12:55:04
- 链接: https://chillcharlie357.github.io/posts/e2853af6/
- 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
评论