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...

相关推荐
写bug写bug18 分钟前
如何正确地对接口进行防御式编程
java·后端·代码规范
Cyanto29 分钟前
Java并发编程面试题
java·开发语言·面试
不超限35 分钟前
Asp.net core 使用EntityFrame Work
后端·asp.net
在未来等你41 分钟前
互联网大厂Java求职面试:AI大模型与云原生技术的深度融合
java·云原生·kubernetes·生成式ai·向量数据库·ai大模型·面试场景
豌豆花下猫1 小时前
Python 潮流周刊#105:Dify突破10万星、2025全栈开发的最佳实践
后端·python·ai
sss191s1 小时前
Java 集合面试题从数据结构到 HashMap 源码剖析详解及常见考点梳理
java·开发语言·数据结构
LI JS@你猜啊1 小时前
window安装docker
java·spring cloud·eureka
书中自有妍如玉1 小时前
.net 使用MQTT订阅消息
java·前端·.net
风铃儿~2 小时前
Spring AI 入门:Java 开发者的生成式 AI 实践之路
java·人工智能·spring
斯普信专业组2 小时前
Tomcat全方位监控实施方案指南
java·tomcat