来源:blog.csdn.net/duxd185120/article/details/109210224
学习一个模块的设计主要是看接口设计,通过接口设计我们就能够从整体知道模块怎么实现的,具体实现就是组装这些接口来进行实现的,知道了模块接口设计,实现也就变得很简单了。
本文主要从aop背景出发点,来自己去想需要哪些接口,就能够描述一个模块的功能设计规则。
AOP产生背景
使用面向对象编程 ( OOP )有一些弊端,当需要为多个不具有继承关系的对象引人同一个公共行为时,例如日志、安全检测等,我们只有在每个对象里引用公共行为,这样程序中就产生了大量的重复代码,程序就不便于维护了,所以就有了一个对面向对象编程的补充,即面向方面编程 ( AOP ), AOP 所关注的方向是横向的,区别于 OOP 的纵向。
什么是AOP
什么是面向方面编程,3个过程:
- 找到横切点:首要目标确定在程序的哪个位置进行横切逻辑
- 横切逻辑(业务代码):横切逻辑代码,这个就是横切业务代码,与aop无关
- 织入:将横切逻辑织入到横切点
既然是横向的编程,那么在我们的程序中,哪些可以作为横线切入点呢?
看下示例代码:
public class Test {
public static void main(String[] args) {
//@1
B b = new B();
//@2
b.method();
//@3
B.say();
}static class B {
//字段
//@4
private String name;
//构造方法
public B() {
//@1.1
}
//对象方法
public void method(){
//@2.2
}
//静态方法
static void say(){
//@3.3
}
}
}
所以我们可以将横切点主要分为两大类:字段、方法。方法又分为很多种,
文章图片
横切点有很多地方,从代码上看得见的,有如下几个地方:
- 使用构造函数创建对象
-
- 构造函数执行
- 对象方法调用
-
- 对象方法执行
- 静态方法调用
-
- 静态方法执行
- 反射读写对象字段
【图文详解 Spring AOP,看完必懂。。】那么怎么去定义一个横切点呢?怎么用一个接口来描述一个横切点呢?
在Java中,一切皆对象,在Java中一个类有2方面内容:字段、方法(构造函数、对象方法、静态方法),java中使用AccessibleObject来抽象公共行为。方法:就是一段可以执行的程序,一段代码。
所以在横切点接口中,首先一个功能就是返回给用户当前横切点,有两种情况:
- 如果横切点作用于对象(对象字段、对象方法、构造函数),则不仅需要返回AccessibleObject,还需要返回当前对象,因为调用通过反射调用对象方法需要传入当前对象。
- 如果横切点作用于类,则仅返回AccessibleObject即可。
那么AOP联盟使用JointPoint接口来定义横切点。
public interface Joinpoint { Object proceed() throws Throwable;
Object getThis();
AccessibleObject getStaticPart();
}
Object proceed() throws Throwable
: 链式调用横切点Object getThis();
返回连接点当前对象。如果当前连接点是静态,比如静态方法,则该方法返回null,因为反射不需要对象,而且静态方法是通过类调用的,压根就没有对象,所以返回null。spring aop不支持静态方法的拦截,所以在spring中这里返回的就是目标对象(被代理对象)AccessibleObject getStaticPart();
返回连接点静态部分,对于连接点是方法,返回的就是Method对象。现在对连接点的设计比较清晰了,然后就是对连接点的扩展了,比如可执行程序(构造方法、Method)的子接口,字段的子接口(aop联盟没有定义,只有方法级别的)。
AOP联盟对连接点接口的设计:
文章图片
比如在MethodInvocation,就是返回Method。
目标2:横切逻辑(增强)抽象定义
增强的抽象,其实就需要连接点信息,毕竟增强是要投入到一个地方的,所以需要连接点信息。
在aop联盟的接口定义:
文章图片
Advice作为一个tag标识,在aop联盟中使用拦截器来作为增强的命名,这里完全可以去掉Interceptor,而直接定义一个MethodAdvice。之所以定义为Interceptor,是因为拦截器命名更符合编程命名规范,让人从命名就知道接口功能。
在MethodInterceptor,传入连接点信息(因为是方法拦截,所以这里是方法级别的连接点接口定义)
Object invoke(MethodInvocation invocation) throws Throwable;
目标3:织入
首先就是怎么织入。织入由两种方案。
- 静态织入:采用自定义类加载器机制。自定义类加载器根据织入规则在加载class文件期间对class文件动手织入横切逻辑,然后将改动后的class文件交给JVM运行。
- 动态织入:由多种选择,动态代理(JDK Proxy)、动态字节码生成技术(cglib)
来一个完整的流程图:
文章图片
Spring AOP的实现基于AOP联盟接口标准设计实现的,全局看下aopalliance有哪些接口以及接口的API设计,我们上面已经分析完了。
AOP联盟的接口很少:
文章图片
近期热文推荐:
1.1,000+ 道 Java面试题及答案整理(2022最新版)
2.劲爆!Java 协程要来了。。。
3.Spring Boot 2.x 教程,太全了!
4.别再写满屏的爆爆爆炸类了,试试装饰器模式,这才是优雅的方式!!
5.《Java开发手册(嵩山版)》最新发布,速速下载!
觉得不错,别忘了随手点赞+转发哦!
推荐阅读
- Java之路|为什么MySQL不推荐使用uuid作为主键()
- 项目实战|SpringBoot个人博客从无到有项目搭建——实战综合介绍
- 程序员|官方都不推荐(为什么MySQL不推荐使用uuid作为主键?究竟有什么坏处)
- 数据库|为啥不能用uuid做MySQL的主键!()
- redis|2021-11-13 记录(Java连接远程Redis的报错信息和解决办法)
- 安全|深入分析H2数据库控制台中无需身份验证的RCE漏洞
- 面试|面试官(看到你熟练性能调优,可以说一下你对MySQL索引的理解())
- Java|Java-抽象类与接口
- 一款简易的Java工作流框架