# dummy-aop **Repository Path**: phial3/dummy-aop ## Basic Information - **Project Name**: dummy-aop - **Description**: 简易的AOP(脱离Spring环境),适合初学者用于研究Spring AOP源码 - **Primary Language**: Unknown - **License**: GPL-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 8 - **Created**: 2024-03-15 - **Last Updated**: 2024-03-15 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 简易的AOP - 不依赖IoC容器,可独立使用 - 支持AspectJ ## 学习方式 - 先把下面这篇《AOP的核心原理简介》看完,理解AOP最核心的概念。 - 然后pull dummy-aop到本地,把测试案例都跑一遍,沿着测试案例debug几遍,把流程搞清楚。 - 最后,可以尝试把dummy-ioc和dummy-aop两个项目整合起来,得到完整的dummy-spring(通过BeanPostProcessor)。 ## AOP的核心原理简介 在一般大众的认知中,AOP就是在方法的前后做一些事情(Spring默认也就是方法级别的AOP)。 这是一个很普通的方法UserService#sayHello。 图片名称 如何在sayHello前后做一些事情呢?最粗暴的做法是: 图片名称 但这并不符合开闭原则,也不通用。如果需要在OrderService#order方法前后也做一些事情,就要把代码拷贝一份。 所以,我们必须将**sayHello**和**sayHello前后要做的事情**进行分离,而分离的目的是为了下次更好的相聚(组合)。 图片名称 Spring AOP的做法是,抽象出以下概念: - `Pointcut` - `Advice` - `Advisor` `Pointcut`俗称切点,可以简单理解为“怎么切/切哪里”,通常是一个**匹配规则**。 比如AspectJ的`AspectJExpressionPointcut`,允许我们配置切点表达式: > execution(* com.bravo.test.service.UserService.sayHello(..)) `Advice`则是具体的**增强逻辑**,即前面说的“方法前后要做的事情”。 而`Advisor` = `Pointcut` + `Advice`。 **对于符合Pointcut规则的目标方法应用Advice,以求在目标方法前后做一些事情。** 所以,上面拆开的sayHello和sayHello前后要做的事现在要产生联系了: 图片名称 Spring把这个匹配过程封装在了AdvisorChainFactory中,代码大致如下: 图片名称 Advisor持有Pointcut,方法匹配成功,则返回advice用于增强当前方法。 尽管在我看来这些`Advisor`、`Advice`、`Pointcut`这些概念已经很清晰,但对于初学者来说可能仍然有点绕。 所以,下面的讲解中,我再做一步简化,只留下Advice的概念,丢弃Pointcut和Advisor(dummy-aop会保留这些概念)。 没有Pointcut怎么知道哪些方法需要增强呢?交给调用者手动组装。比如: 图片名称 讲到这,对于如何实现AOP应该有一个模糊的概念了。 接下来我们讨论最难的两个问题: - 如何把advice嵌入目标方法前后 - 如何链式执行advice 所谓AOP,就是在调用目标方法前后额外执行一些逻辑。整个过程大致如下: 图片名称 Method#invoke负责执行目标方法,额外的一些事情交给Advice去做。 在这里,Spring又抽象出了一个新的概念:`MethodInvocation`。它把上面整个流程进行了封装。 即把“Method执行前后需要额外做一些操作”这个过程抽象成MethodInvocation(method和method之前的操作打包在一块)。 图片名称 Method是Java对**方法**的抽象,它包含一个方法的所有信息,如名称、参数和返回类型。 而MethodInvocation则是Spring对**方法调用**的抽象,更偏向**动态**的概念,调用proceed时会额外执行Advice。 MethodInvocation最重要的实现类是ReflectiveMethodInvocation,其主要成员变量包括: - Method - MethodInterceptorChain 图片名称 想要使用MethodInvocation调用方法,则必然要先经过一串Interceptor。 > MethodInterceptor是AOP联盟的,Advice是Spring自己定义的。Spring底层把Advice适配成MethodInterceptor。 > MethodInterceptor比Advice更加见名知意,也和MethodInvocation更搭。 图片名称 接着,我们使用JDK动态代理为userService生成代理对象。代理对象会将一次方法调用委托到目标对象,但在此之前会执行advice: 图片名称 那么,如何产生链式调用呢? 图片名称 MethodInvocation就是Filter模式中的FilterChain,持有Interceptor并且负责推进下一个Interceptor。 图片名称 上面这个案例是极简的AOP,我放在 [设计模式那些事儿](https://gitee.com/bravo1988/design-pattern) 中,搞懂以后再研究dummy-aop。 图片名称 搞懂以后再看dummy-aop的代码。 ## 推荐 - [dummy-ioc](https://gitee.com/bravo1988/dummy-ioc) - [设计模式那些事儿](https://gitee.com/bravo1988/design-pattern)