Spring AOP = 责任链模式 + 代理模式

这里就不扯什么是AOP以及AspectJ的历史了,在一般大众的认知中,AOP就是在方法的前后做一些事情(Spring默认也就是方法级别的AOP)。接下来,让我们一步步实现AOP。

这是一个很普通的方法UserService#sayHello。

如何在sayHello前后做一些事情呢?最粗暴的做法是:

但这并不符合开闭原则,也不通用。如果需要在OrderService#order方法前后也做一些事情,就要把代码拷贝一份。

所以,我们必须将sayHello和sayHello前后要做的事情进行分离,而分离的目的是为了下次更好的相聚(组合)。

Spring AOP的做法是,抽象出以下概念:

  • Pointcut
  • Advice
  • Advisor

Pointcut俗称切点,可以简单理解为"怎么切/切哪里",也就是一个匹配规则,比如我们常见的AspectJExpressionPointcut,允许我们配置切点表达式:

execution(* com.bravo.test.service.UserService.sayHello(..))

Advice则是具体的增强逻辑,即前面说的"方法前后要做的事情"。

而Advisor=Pointcut+Advice。

对于符合Pointcut规则的目标方法应用Advice,在目标方法前后做一些事情。

尽管在我看来这些概念已经很清晰,但对于初学者来说还是有点绕。所以,这里再做一步简化,只留下Advice的概念,丢弃Pointcut和Advisor。没有Pointcut怎么知道哪些方法需要增强呢?交给调用者手动组装。比如:

当然,Spring内部有一个匹配过程,代码大致如下(这里不是Spring的源码):

Advisor持有Pointcut,方法匹配成功,则返回advice用于增强

讲到这,对于如何实现AOP应该有一个模糊的概念了。

接下来我们讨论最难的两个问题:

  • 如何把advice嵌入目标方法前后
  • 如何链式执行advice

在这里,Spring又抽象出了一个新的概念:MethodInvocation。

这是啥?Spring很清楚,所谓AOP,就是在调用目标方法前后额外执行一些内容。Java的反射已经封装好Method这个类,所以整个过程就是:

那我能不能把这个过程也封装一下呢?我把"Method执行前后需要额外做一些操作"这个过程抽象成MethodInvocation(方法执行)。

里面只定义一个方法proceed,表示执行方法,而且执行的时候要自动把advice也执行掉。

然后,配套的还有MethodInterceptor:

这又是啥?通俗讲就是方法拦截器,在执行方法前做些事情。在Spring中MethodInterceptor继承自Advice,大家直接看成Advice即可。

所以,现在变成了这样:

把经过Interceptor执行Method的这个过程封装成MethodInvocation

接着,我们使用JDK动态代理为userService生成代理对象。代理对象会将一次方法调用委托到目标对象,但在此之前会执行advice:

那么,如何产生链式调用呢?

MethodInvocation就是Filter模式中的FilterChain,持有Interceptor并且负责推进下一个Interceptor

具体代码放在gitee了:

gitee.com/bravo1988/d...

相关推荐
javadaydayup几秒前
别再逐个注入了!@Autowired 批量获取接口实现类的核心逻辑拆解
spring
MarkGosling2 分钟前
【开源项目】网络诊断告别命令行!NetSonar:开源多协议网络诊断利器
运维·后端·自动化运维
hi0_63 分钟前
03 数组 VS 链表
java·数据结构·c++·笔记·算法·链表
Codebee5 分钟前
OneCode3.0 VFS分布式文件管理API速查手册
后端·架构·开源
朝如青丝暮成雪_6 分钟前
java的三大特征
java
用户0595661192097 分钟前
Java 8 + 特性与 spring Boot 及 hibernate 等最新技术实操内容全解析
java·架构·设计
_新一7 分钟前
Go 调度器(二):一个线程的执行流程
后端
estarlee10 分钟前
腾讯云轻量服务器创建镜像免费API接口教程
后端
长安有故里y23 分钟前
tomcat设置预防host头攻击
java·tomcat·firefox
生产队队长24 分钟前
Tomcat问题:启动脚本startup.bat中文乱码问题解决
java·ajax·tomcat