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

相关推荐
hrrrrb4 分钟前
【Spring Security】Spring Security 概念
java·数据库·spring
小信丶4 分钟前
Spring 中解决 “Could not autowire. There is more than one bean of type“ 错误
java·spring
周杰伦_Jay1 小时前
【Java虚拟机(JVM)全面解析】从原理到面试实战、JVM故障处理、类加载、内存区域、垃圾回收
java·jvm
摇滚侠2 小时前
Spring Boot 3零基础教程,IOC容器中组件的注册,笔记08
spring boot·笔记·后端
程序员小凯5 小时前
Spring Boot测试框架详解
java·spring boot·后端
豐儀麟阁贵5 小时前
基本数据类型
java·算法
_extraordinary_5 小时前
Java SpringMVC(二) --- 响应,综合性练习
java·开发语言
你的人类朋友5 小时前
什么是断言?
前端·后端·安全
程序员 Harry6 小时前
深度解析:使用ZIP流式读取大型PPTX文件的最佳实践
java
程序员小凯6 小时前
Spring Boot缓存机制详解
spring boot·后端·缓存