Spring AOP 实现原理分析
小橘子🍊

前言

本文是关于 spring aop 实现原理的分析文章,因为 spring 源码博大精深,对于 aop 实现的细节部分不可能通过此一篇文章讲解清楚,所以本文只是从整体的角度来看 aop 的实现,虽然细节部分不会细说,但是对于理解其实现及分析其执行过程而言足以。另外本文是建立在你已经对 spring 的 ioc 实现原理有一定的理解基础之上,特别是清楚 spring 的标签解析以及 spring 管理的 bean 的声明周期。在写这篇文章之前我先大致看过了 spring-framework 源码的 aop 部分,在看的过程中还写了一小部分注释来帮助自己理解,这部分内容我已经将其放到了我的 github 之上,欢迎欢迎自取。 整个源码是我从官方 fork 下来的,除了注释部分我没做任何改动,另外在其中加了一个 spring-example 模块,用来写测试样例,方便源码分析。原项目是用 gradle 构建的,对于不熟悉 gradle 项目的同学可以参考项目根目录下的 import-into-xxx.md 文档来将项目导入到自己熟悉的 ide 中(其实我 fork 下来也是第一次接触 gradel 工程),原项目 build.gradle 文件中有很多不必要的 task,我已经将其注释掉,由此来提高 build 的速度。

aop 测试样例

在分析 aop 实现原理之前,我们需要先看两个 aop 测试代码,具体的源码分析过程就是基于这两个测试代码的,源码欢迎自取。

测试代码一

主函数 top.aprilyolies.example.aop.AopApp

1
2
3
4
5
6
7
public class AopApp {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring-aop.xml");
TestBean bean = (TestBean) context.getBean("test");
bean.test();
}
}

切面定义 top.aprilyolies.example.aop.AspectJBean

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
@Aspect
public class AspectJBean {
@Pointcut("execution(* *.test*(..))") // 这个可能就是引介增强方法,这里可能就是切点
public void test() {}

@Before("test()") // 这个可能就是切点增强方法
public void beforeTest() {
System.out.println("beforeTest");
}

@After("test()")
public void afterTest() {
System.out.println("afterTest");
}

@Around("test()")
public Object aroundTest(ProceedingJoinPoint p) {
Object o = null;
System.out.println("aroundBefore");
try {
o = p.proceed();
} catch (Throwable throwable) {
throwable.printStackTrace();
}
System.out.println("aroundAfter");
return o;
}

}

测试 bean top.aprilyolies.example.aop.TestBean

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class TestBean {
public TestBean() {
System.out.println("TestBean constructor");
}

public void test() {
System.out.println("test method....");
System.out.println("----------");
test1();
System.out.println("----------");
}

public void test1() {
System.out.println("test1 method....");
}
}

spring-aop.xml

1
2
3
4
5
6
7
8
9
10
11
12
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">

<aop:aspectj-autoproxy/>

<bean id="test" class="top.aprilyolies.example.aop.TestBean"/>
<bean id="aspectJBean" class="top.aprilyolies.example.aop.AspectJBean"/>
</beans>

执行结果

1
2
3
4
5
6
7
8
9
TestBean constructor    // 构造函数执行
aroundBefore // around 增强
beforeTest // before 增强
test method.... // test* 方法
----------
test1 method....
----------
aroundAfter // around 增强
afterTest // after 增强

测试样例很简单,其实就是定义了一个切面类,里边描述了一些切面信息,比如这里就是对任意包下的任意类,返回值不限的任意 test* 方法进行增强,分为三种类型的增强,after、before、around。也就是说我在调用 test* 方法时,上述的三个方法会在何时的位置调用,理解这个后再看上边的执行结果应该就很清楚了,至于为什么会进行这样的调用,就是本文分析的重点了,稍后再说,再看第二个示例程序。

测试代码二

主函数

1
2
3
4
5
6
7
public class AopApp {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring-aop-expose.xml");
TestBean bean = (TestBean) context.getBean("test");
bean.test();
}
}

测试 bean top.aprilyolies.example.aop.TestBean

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class TestBean {
public TestBean() {
System.out.println("TestBean constructor");
}

public void test() {
System.out.println("test method....");
TestBean testBean = (TestBean) AopContext.currentProxy();
System.out.println("----------");
testBean.test1();
test1();
System.out.println("----------");
}

public void test1() {
System.out.println("test1 method....");
}
}

spring-aop-expose.xml

1
2
3
4
5
6
7
8
9
10
11
12
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">

<aop:aspectj-autoproxy expose-proxy="true"/>

<bean id="test" class="top.aprilyolies.example.aop.TestBean"/>
<bean id="aspectJBean" class="top.aprilyolies.example.aop.AspectJBean"/>
</beans>

切面定义类不变,看执行结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
TestBean constructor
aroundBefore
beforeTest
test method....
----------
aroundBefore
beforeTest
test1 method....
aroundAfter
afterTest
----------
aroundAfter
afterTest

其实和测试代码一的逻辑基本一致,只是在 spring 的配置文件中,<aop:aspectj-autoproxy expose-proxy="true"/> 标签多了一个 expose-proxy=”true” 属性,然后 TestBean#test 方法中并不是直接调用 TestBean#test1 方法,而是从 AopContext 中拿到当前的代理类,再调用它的 test1 方法,可以看到,上述的三个增强方法也都执行了,而直接通过用户代码调用 test1 方法,以上的增强方法就不会发生调用。这里说明,如果我们自己的用户代码在内部调用其他方法时,需要被调用的方法同样得到增强,那么就需要采用测试代码二那样的方式获取到当前的代理类,然后进行对应方法的调用,直接进行调用的方式是不对得到增强的。

<aop:aspectj-autoproxy/> 标签解析

如果对 spring 的标签解析原理熟悉,那么你在分析 aop 实现原理时,就一定会想到从 <aop:aspectj-autoproxy/> 标签的解析开始,它是启动 spring aop 的根本。spring 本身对于标签的解析实现很有规则,总的就是将标签分为默认标签和自定义标签。从 DefaultBeanDefinitionDocumentReader#parseBeanDefinitions 方法就可以看出这个区别。

org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader#parseBeanDefinitions

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/**
* Parse the elements at the root level in the document:
* "import", "alias", "bean".
* @param root the DOM root element of the document
*/
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
if (delegate.isDefaultNamespace(root)) { // 这个分支是解析默认的 Namespace 标签
NodeList nl = root.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (node instanceof Element) {
Element ele = (Element) node;
if (delegate.isDefaultNamespace(ele)) {
parseDefaultElement(ele, delegate);
}
else {
delegate.parseCustomElement(ele);
}
}
}
}
else {
delegate.parseCustomElement(root); // 这个分支就是解析用户自定义的 Namespace 标签
}
}

对于默认标签而言,从下面的代码可以看出主要是包含 import、alias、bean、beans 四种标签。

org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader#parseDefaultElement

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 解析默认的标签,可以看出来有 import、alias、bean、beans
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
importBeanDefinitionResource(ele);
}
else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
processAliasRegistration(ele);
}
else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
processBeanDefinition(ele, delegate);
}
else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
// recurse
doRegisterBeanDefinitions(ele);
}
}

而对于非默认的标签,spring 则是通过对应标签命名空间的 NamespaceHandler 来注册对应空间下不同标签的解析器来完成解析的,这种 NamespaceHandler 的命名很规范,比如我们现在是分析 aop 实现,核心标签就是 <aop:aspectj-autoproxy/>,其对应的命名空间就是 aop,所以我们只需要打开其对应的 AopNamespaceHandler 就可以分析 spring 对于相应的标签做了啥处理。

org.springframework.aop.config.AopNamespaceHandler

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class AopNamespaceHandler extends NamespaceHandlerSupport {

/**
* Register the {@link BeanDefinitionParser BeanDefinitionParsers} for the
* '{@code config}', '{@code spring-configured}', '{@code aspectj-autoproxy}'
* and '{@code scoped-proxy}' tags.
*/
@Override
public void init() {
// In 2.0 XSD as well as in 2.1 XSD.
registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser());
registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());
registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator());

// Only in 2.0 XSD: moved to context namespace as of 2.1
registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
}

}

好了,看到这个后我们就清楚了,对于 aop 命名空间,它下边是有四种类型的标签的,我们这里只用到了 aspectj-autoproxy,就只分析这一个。通过看类名就知道,不同的标签对应着一个 BeanDefinitionParser,这是一个接口,里边只有一个 BeanDefinitionParser#parse 方法,那就直接看 AspectJAutoProxyBeanDefinitionParser#parse 方法如下:

1
2
3
4
5
public BeanDefinition parse(Element element, ParserContext parserContext) {
AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element); // 主要就是注册了一个 AnnotationAwareAspectJAutoProxyCreator,并对 <aop:aspectj-autoproxy/> 标签的 proxy-target-class 和 expose-proxy 属性的处理
extendBeanDefinition(element, parserContext);
return null;
}

主要就是两行代码,对于第二行代码,是一个对于当前标签的子标签的处理,因为这里没用到,所以我直接就忽略了。重点关注第一行代码,从名字就知道,核心就是向 spring 容器注册一个 AspectJAnnotationAutoProxyCreator 实例,进去后看实现:

1
2
3
4
5
6
7
8
9
// 主要就是注册了一个 AnnotationAwareAspectJAutoProxyCreator,并对 <aop:aspectj-autoproxy/> 标签的 proxy-target-class 和 expose-proxy 属性的处理
public static void registerAspectJAnnotationAutoProxyCreatorIfNecessary(
ParserContext parserContext, Element sourceElement) {
// 尝试向 DefaultListableBeanFactory 中注册 AnnotationAwareAspectJAutoProxyCreator 对应的 bean,如果已存在,则注册优先级较高的那个
BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(
parserContext.getRegistry(), parserContext.extractSource(sourceElement));
useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement); // 对于 <aop:aspectj-autoproxy/> 标签 proxy-target-class 和 expose-proxy 属性的处理
registerComponentIfNecessary(beanDefinition, parserContext); // 核心就是注册 AnnotationAwareAspectJAutoProxyCreator 对应的 beanDefinition(封装为 BeanComponentDefinition)
}

一共就三行代码,先看第一行,直接点进去可以看到代码是这样的,关于其作用我已经通过注释的方式进行标注了,根本的实现就是一个类似标签解析生成 BeanDefinition 的过程,如果你看过标签解析的话,那么你对这串代码一定不会陌生,而且 BeanDefinition 这个实例你也一定很耳熟。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
@Nullable	// 尝试向 DefaultListableBeanFactory 中注册 AnnotationAwareAspectJAutoProxyCreator 对应的 bean,如果已存在,则注册优先级较高的那个
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(
BeanDefinitionRegistry registry, @Nullable Object source) {
// 尝试向 DefaultListableBeanFactory 中注册 AnnotationAwareAspectJAutoProxyCreator 对应的 bean,如果已存在,则注册优先级较高的那个
return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
}

@Nullable // 尝试向 DefaultListableBeanFactory 中注册 cls 对应的 bean,如果已存在,则注册优先级较高的那个
private static BeanDefinition registerOrEscalateApcAsRequired(
Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {

Assert.notNull(registry, "BeanDefinitionRegistry must not be null");

if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) { // 这里是指已存在对应的 bean,那么就看谁的优先级高
BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
int requiredPriority = findPriorityForClass(cls);
if (currentPriority < requiredPriority) {
apcDefinition.setBeanClassName(cls.getName());
}
}
return null;
}

RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
beanDefinition.setSource(source);
beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); // 指明该 bean 在 spring 容器中的身份
registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
return beanDefinition;
}

细节就不在深究了,因为牵扯的代码非常多,这里我们只需要清楚第一行代码就是向 spring 容器注册了一个 AnnotationAwareAspectJAutoProxyCreator 类型的类,在 spring 容器启动过程中,会根据既定的条件完成该类的初始化及生命周期方法的调用,对了需要注意,该类对应的实例在 spring 容器中的唯一标志符就是 AUTO_PROXY_CREATOR_BEAN_NAME = "org.springframework.aop.config.internalAutoProxyCreator";

再看第二行代码,逻辑很简单,就是看当前标签的属性,如果有 proxy-target-class 或者 expose-proxy 属性,那么就将该属性的值设置到第一行代码注册的 AnnotationAwareAspectJAutoProxyCreator 类对应的 BeanDefinition 中去。这样在通过 BeanDefinition 构建 bean 实例时,通过标签设置的属性值就会被注入到该 bean 中了。具体实现就是通过下边的代码,每个方法的作用我也进行了注释,很容易理解。还记得我们开篇的第二个测试代码嘛?标签中的 expose-proxy="true" 属性值就是在这里被解析的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// 对于 <aop:aspectj-autoproxy/> 标签 proxy-target-class 和 expose-proxy 属性的处理
private static void useClassProxyingIfNecessary(BeanDefinitionRegistry registry, @Nullable Element sourceElement) {
if (sourceElement != null) {
boolean proxyTargetClass = Boolean.parseBoolean(sourceElement.getAttribute(PROXY_TARGET_CLASS_ATTRIBUTE));
if (proxyTargetClass) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
}
boolean exposeProxy = Boolean.parseBoolean(sourceElement.getAttribute(EXPOSE_PROXY_ATTRIBUTE));
if (exposeProxy) {
AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
}
}
}

// 为 AUTO_PROXY_CREATOR_BEAN_NAME 对应的 BeanDefinition 添加一个 proxyTargetClass 属性,值为 true
public static void forceAutoProxyCreatorToUseClassProxying(BeanDefinitionRegistry registry) {
if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
BeanDefinition definition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
definition.getPropertyValues().add("proxyTargetClass", Boolean.TRUE);
}
}
// 为 AUTO_PROXY_CREATOR_BEAN_NAME 对应的 BeanDefinition 添加一个 exposeProxy 属性,值为 true
public static void forceAutoProxyCreatorToExposeProxy(BeanDefinitionRegistry registry) {
if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
BeanDefinition definition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
definition.getPropertyValues().add("exposeProxy", Boolean.TRUE);
}
}

再看第三行代码,没啥其他内容,就仅仅是一个注册 BeanDefinition 的过程,对于我们的 aop 原理分析而言,不是很紧要,仅贴出来实现就行。

1
2
3
4
5
6
7
// 核心就是注册 AnnotationAwareAspectJAutoProxyCreator 对应的 beanDefinition(封装为 BeanComponentDefinition)
private static void registerComponentIfNecessary(@Nullable BeanDefinition beanDefinition, ParserContext parserContext) {
if (beanDefinition != null) {
parserContext.registerComponent(
new BeanComponentDefinition(beanDefinition, AopConfigUtils.AUTO_PROXY_CREATOR_BEAN_NAME));
}
}

好了,到这里关于 <aop:aspectj-autoproxy/> 标签的解析过程就算完成了,进行总结一下该过程,核心就是根据 AnnotationAwareAspectJAutoProxyCreator 类创建一个对应的 BeanDefinition,然后看该标签是否有上述的两个属性值,如果就的话,就将对应的属性值填充到当前 BeanDefinition 中,最后就是将该 BeanDefinition 封装为 BeanComponentDefinition 注册到 parserContext 中。

代理类的生成

上边已经说完了标签解析的过程,知道了现在 spring 容器中存在一个 AnnotationAwareAspectJAutoProxyCreator 类对应的 BeanDefinition,在接下来的过程,spring 会根据 BeanDefinition 实现的不同声明周期接口,在不同的初始化阶段来完成对应方法的调用。既然这样,我们现在就关注一下 AnnotationAwareAspectJAutoProxyCreator 实现了什么接口。直接查看它的继承关系图。

AnnotationAwareAspectJAutoProxyCreator 继承图

直接看好像没有什么熟悉的声明周期接口对吧,但是如果你顺着继承关系逐个往上找,就会看到在其父类 AbstractAutoProxyCreator 中实现了一个 SmartInstantiationAwareBeanPostProcessor 接口,看过 spring ioc 实现原理的小伙伴应该对 BeanPostProcessor 这样的接口十分敏感,它意味着在 bean 的初始化不同阶段,spring 会完成对实现该类接口的 bean 的对应方法的调用,这里也不例外。当然直接通过 idea 的 diagram 绘制能更清楚的看出 AnnotationAwareAspectJAutoProxyCreator 实现的其它接口,但是这里我们只关心 SmartInstantiationAwareBeanPostProcessor。

AnnotationAwareAspectJAutoProxyCreator 继承体系

这里的 SmartInstantiationAwareBeanPostProcessor 接口又继承自 InstantiationAwareBeanPostProcessor,这样 AnnotationAwareAspectJAutoProxyCreator 要实现的方法就多了,应该重点关注哪个呢?其实我也不是很清楚,但是可以通过 debug 的方式来跟踪,下大致看一下全部的实现方法,发现所有的实现方法中,只有两个方法的实现逻辑稍微复杂且在 bean 的构建过程中被调用到,他们就是 AbstractAutoProxyCreator#postProcessBeforeInstantiationAbstractAutoProxyCreator#postProcessAfterInitialization,我在这个两个方法第一行代码处各打一个断点,通过 debug 的方式,可以知道第一个方法的出口是返回的 null,跟我们期望的代理类生成没有关系,直接排除,那么可以暂时认定代理类的生成是通过 AbstractAutoProxyCreator#postProcessAfterInitialization 方法实现的。那么接下来就看在该方法中做了什么。

1
2
3
4
5
6
7
8
9
10
@Override	// 尝试从缓存中获取代理 bean,没有的话进行构建,核心就是构建 enhancer,根据 enhancer 构建代理类 class,然后通过 class 构建代理类实例,最后将 callbacks 设置到其中
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
return wrapIfNecessary(bean, beanName, cacheKey); // 核心就是构建 enhancer,根据 enhancer 构建代理类 class,然后通过 class 构建代理类实例,最后将 callbacks 设置到其中
}
}
return bean;
}

从上述代码可以看到这里是一个从缓存中获取代理类,如果获取的结果和参数传入的 bean 不一致,就对传入的 bean 进行尝试代理的过程。那么这个参数传入的 bean 究竟是什么呢??我通过 debug 的方式进行查看,结果如下:

被处理的 bean 类型

原来就是我们样例代码中的 TestBean,所以到这里一个大致的过程就需要明白了,在 spring 配置文件中,我们指定了 TestBean 来交给 spring 容器管理,在 spring 对该 bean 进行创建时,spring 会用各种 BeanPostProcessor 接口实现类对应的方法来对正在构建的 bean 进行处理,拿我们的样例程序来说就是:实现了 BeanPostProcessor 接口的 AnnotationAwareAspectJAutoProxyCreator 实例的 AbstractAutoProxyCreator#postProcessAfterInitialization 方法来对 TestBean 进行处理,具体的处理过程是啥样呢?就是上边代码框中那样,从注释可以知道就是一个对原 bean(TestBean)进行代理的过程。下边继续看这个代理 bean 如何构建的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
/**
* Wrap the given bean if necessary, i.e. if it is eligible for being proxied.
* @param bean the raw bean instance
* @param beanName the name of the bean
* @param cacheKey the cache key for metadata access
* @return a proxy wrapping the bean, or the raw bean instance as-is
*/ // 判断是否需要代理,如果是,获取满足 beanClass 的 advisor,然后构建代理类:验证代理工厂长持有的目标类,然后构建 enhancer,根据 enhancer 构建代理类 class,然后通过 class 构建代理类实例,最后将 callbacks 设置到其中
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean; // 无需代理,直接返回
}
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean; // 基础类和应跳过的类直接返回
}

// Create proxy if we have advice. // 获取满足 beanClass 的 advisor,进行过排序
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE); // 所以这个集合存放的是对应的 bean 是否增强的信息
Object proxy = createProxy( // 验证代理工厂长持有的目标类,然后构建 enhancer,根据 enhancer 构建代理类 class,然后通过 class 构建代理类实例,最后将 callbacks 设置到其中
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
// 所以这个集合存放的是对应的 bean 是否增强的信息
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}

上边的代码很好理解,前半部分就是一些验证,看被处理的 bean 是否满足被代理需求。如果不满足就会直接返回 bean,否则就会获取 specificInterceptors 集合,这个 specificInterceptors 集合的获取过程很麻烦,反正我是没有去逐行的看源码。仅仅是从方法名来判断各个步骤做了啥事情,我将能够展示程序执行脉络的代码贴出来,然后给出执行的结果,这样就算不通读源码,也能够理解其原理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@Override
@Nullable // 获取满足 beanClass 的 advisor,进行过排序
protected Object[] getAdvicesAndAdvisorsForBean(
Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
// 获取满足 beanClass 的 advisor,进行过排序
List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
if (advisors.isEmpty()) {
return DO_NOT_PROXY; // 如果没有增强器,就不需要进行代理
}
return advisors.toArray();
}

protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
List<Advisor> candidateAdvisors = findCandidateAdvisors(); // 获取候选的增强器
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName); // 获取能够使用的增强器
extendAdvisors(eligibleAdvisors); // 看 advisors 是否有切面增强器,有的话就在首位添加一个 DefaultPointcutAdvisor(ExposeInvocationInterceptor.ADVISOR)
if (!eligibleAdvisors.isEmpty()) {
eligibleAdvisors = sortAdvisors(eligibleAdvisors); // 对 advisors 进行排序
}
return eligibleAdvisors;
}

代码的主干就上边那些,其实就是一个获取有效增强的过程,什么是有效增强嗯?通过 debug 的方式直接查看其内容如下,不难看出所谓的增加就是我们在切面类中定义的那些切面方法,即通过 @Before、@After、@Around 注解标注的方法。

候选的增强集合

增强对应的方法

我们已经知道获取的结果了,那么该结果怎么来的呢?还是上边的代码,一共就四条逻辑,第一条逻辑 findCandidateAdvisors,看方法名就知道是获取候选的增强。里边的代码比较冗长,但核心就是获取所有切面类中所有定义的增强。至于我们的 @Before、@After、@Around 注解式如何被解析为 Advisor 呢?我没研究过,但就算是猜也能猜出大概了,切面类不是有 @Aspect 注解吗?它也是交由 spring 管理的,那么 spring 自然是会关注这个注解的,当对 bean 进行构建时,如果发现该 bean 有 @Aspect 注解,就遍历该 bean 的所有方法,看方法上是否有上述的三种增强注解(或许其他注解也是被解释为增强哈),如果有就将当前切面 bean 和对应的增强缓存起来,以便后边获取。当然这只是我的个人猜想,没去看源码,如果我猜的不对,还请指出。总之第一条逻辑就是获取全部切面类的增强就对了。

第二条逻辑由 findAdvisorsThatCanApply 来实现,看方法名就知道是从全部的增强中获取当前被处理的 bean 能够使用的增强。怎么实现呢?我也不想看源码,直接猜吧,猜错也没事,方法名确实就是这个意思(其实还是大致看了一下源码的)。我们在切面类中不是指定了切点信息吗??就是这个 @Pointcut("execution(* *.test*(..))") 意思就是当前切面类的增强适用于指定的全部切点。那么 findAdvisorsThatCanApply 方法就一定是根据切点表达式来分析我们当前正在处理的 bean 是否满足切点规则。如果满足的话,那么该增强就会被添加到返回集合,否则直接丢弃。最终 findAdvisorsThatCanApply 返回的就是能够应用在当前 bean 的增强了。

第三条逻辑由 extendAdvisors 实现,没错的话我们在切面类中定义的增强只有三个对吗??为什么最终返回结果有四个呢??其实就是在这条逻辑中添加的,根本是执行的下边的代码,也就是说如果我们获取的可用增强中,如果有切面增强类,那么就一定会在增强链表的第一个位置加入一个 ExposeInvocationInterceptor.ADVISOR,至于作用嘛,暂时没研究,这个不影响后边的分析。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 看 advisors 是否有切面增强器,有的话就在首位添加一个 DefaultPointcutAdvisor(ExposeInvocationInterceptor.ADVISOR)
public static boolean makeAdvisorChainAspectJCapableIfNecessary(List<Advisor> advisors) {
// Don't add advisors to an empty list; may indicate that proxying is just not required
if (!advisors.isEmpty()) {
boolean foundAspectJAdvice = false;
for (Advisor advisor : advisors) {
// Be careful not to get the Advice without a guard, as this might eagerly
// instantiate a non-singleton AspectJ aspect...
if (isAspectJAdvice(advisor)) { // 看是否是切面增强器
foundAspectJAdvice = true;
break;
}
} // (ExposeInvocationInterceptor.ADVISOR 是放在首位的
if (foundAspectJAdvice && !advisors.contains(ExposeInvocationInterceptor.ADVISOR)) {
advisors.add(0, ExposeInvocationInterceptor.ADVISOR);
return true;
}
}
return false;
}

最后一个逻辑就是对所有的增强进行排序,根本就是链表的排序,采用的是自定义的排序比较器,详细的可以自行分析源码,所以上边展示的最终返回的四个 eligibleAdvisor,就是通过上边四个逻辑来得到。回到我们的出发点,即AbstractAutoProxyCreator#wrapIfNecessary 方法的的 getAdvicesAndAdvisorsForBean 这一行,我们已经拿到了四个增强,接下来我们就是根据这个增强数组来构建代理类。

代理类的构建过程也很麻烦,如果要逐行看代码那又是个大工程,这里实质是从宏观的角度来看代码逻辑,能够理解 aop 实现原理即可,直接进入到 AbstractAutoProxyCreator#createProxy 方法中,我已经写了蛮多注释了,所以这里只是总结性的说一下逻辑,其实核心就是构建 proxyFactory,最后通过它来构建代理类,准备的工作包括设置代理类型,是采用 jdk 原生代理呢还是采用 cglib 进行代理。将增强填充到这里构建的 proxyFactory 中,包括之前获取到的增强(本例是四个)和 spring 容器中存在的共用增强。将当前实例的必要字段填充到 proxyFactory 代理工厂中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
@Nullable Object[] specificInterceptors, TargetSource targetSource) { // TargetSource 封装了我们的目标实例

if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
}

ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.copyFrom(this); // 当前类的属性复制到 ProxyFactory 中

if (!proxyFactory.isProxyTargetClass()) { // 这里就是判断代理目标类还是接口分别对应 cglib 和 jdk 代理方式
if (shouldProxyTargetClass(beanClass, beanName)) { // 看是否属性值指定了 org.springframework.aop.framework.autoproxy.AutoProxyUtils.preserveTargetClass,这种情况采用目标类代理方式 cglib
proxyFactory.setProxyTargetClass(true); // 这里设置代理方式为 cglib
}
else { // 看目标 class 是否有可以代理的接口,有的话将接口 class 添加到 proxyFactory 中,否则设置代理方式为代理目标类
evaluateProxyInterfaces(beanClass, proxyFactory);
}
}
// 获取公有的 interceptors,然后和 specificInterceptors 一起构建为 advisors 返回
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
proxyFactory.addAdvisors(advisors);
proxyFactory.setTargetSource(targetSource); // 这个参数持有了代理目标
customizeProxyFactory(proxyFactory);

proxyFactory.setFrozen(this.freezeProxy);
if (advisorsPreFiltered()) { // advisors 预过滤
proxyFactory.setPreFiltered(true);
}
// 验证代理工厂长持有的目标类,然后构建 enhancer,根据 enhancer 构建代理类 class,然后通过 class 构建代理类实例,最后将 callbacks 设置到其中
return proxyFactory.getProxy(getProxyClassLoader());
}

这样通过上边的代码,我们构建出了 proxyFactory 代理工厂,向其中填充了增强集合,同时设置了代理类型,还将当前实例的一些字段值拷贝到了 proxyFactory 代理工厂,最后就是根据该代理工厂来构建代理类。核心就是 ProxyFactory#getProxy(java.lang.ClassLoader) 方法,它就一行代码 return createAopProxy().getProxy(classLoader);,先看第一段其根本执行的是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
Class<?> targetClass = config.getTargetClass(); // 执行到这里,说明采用 cglib 代理方式
if (targetClass == null) {
throw new AopConfigException("TargetSource cannot determine target class: " +
"Either an interface or a target is required for proxy creation.");
} // 目标类是接口或者是 Proxy 接口实现类,那么进行 jdk 代理
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
return new ObjenesisCglibAopProxy(config);
}
else {
return new JdkDynamicAopProxy(config); // 这里就是进行 jdk 代理方式
}
}

就是一个创建 AopProxy 的过程,创建出来的感觉就像是一个工厂类吧,因为我们最终还是调用了它的 getProxy 方法。我们的正在处理的目标 bean 为 TestBean,在经过上边代码的条件判断后会返回 ObjenesisCglibAopProxy 实例, 也就是说我们的代理类应该是采用的 cglib 代理方式,至于为什么那就看上边代码逻辑喽。本文只会对 cglib 的代理方式进行说明,jdk 的代理方式应该整体的逻辑差不多,自行分析即可。

return createAopProxy().getProxy(classLoader);,先看第一段就是获取了 ObjenesisCglibAopProxy 实例,我们调用它的 getProxy 方法,它的根本实现就是调用的下边的代码。这里我们看到了用于创建代理类的 Enhancer 实例,所以后边的代码也就不用再深究了,只需要知道这里最终返回的就是一个正在被处理的 bean 的代理类就行了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
@Override	// 验证代理工厂长持有的目标类,然后构建 enhancer,根据 enhancer 构建代理类 class,然后通过 class 构建代理类实例,最后将 callbacks 设置到其中
public Object getProxy(@Nullable ClassLoader classLoader) {
if (logger.isTraceEnabled()) {
logger.trace("Creating CGLIB proxy: " + this.advised.getTargetSource());
}

try { // advised 就是代理工厂实例
Class<?> rootClass = this.advised.getTargetClass();
Assert.state(rootClass != null, "Target class must be available for creating a CGLIB proxy");

Class<?> proxySuperClass = rootClass;
if (rootClass.getName().contains(ClassUtils.CGLIB_CLASS_SEPARATOR)) { // 这里目标类本身就是 cglib 代理类
proxySuperClass = rootClass.getSuperclass();
Class<?>[] additionalInterfaces = rootClass.getInterfaces();
for (Class<?> additionalInterface : additionalInterfaces) {
this.advised.addInterface(additionalInterface); // 获取真实类的接口信息存入代理工厂实例
}
}

// Validate the class, writing log messages as necessary.
validateClassIfNecessary(proxySuperClass, classLoader); // 验证被代理类的信息,包括方法的修饰符

// Configure CGLIB Enhancer...
Enhancer enhancer = createEnhancer(); // cglib 代理增强器
if (classLoader != null) {
enhancer.setClassLoader(classLoader);
if (classLoader instanceof SmartClassLoader &&
((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
enhancer.setUseCache(false);
}
}
enhancer.setSuperclass(proxySuperClass);
enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE); // 命名规则
enhancer.setStrategy(new ClassLoaderAwareUndeclaredThrowableStrategy(classLoader));
// 获取 Callback 数组,包括 mainCallbacks 和 fixedCallbacks 两个部分
Callback[] callbacks = getCallbacks(rootClass);
Class<?>[] types = new Class<?>[callbacks.length];
for (int x = 0; x < types.length; x++) {
types[x] = callbacks[x].getClass();
}
// fixedInterceptorMap only populated at this point, after getCallbacks call above
enhancer.setCallbackFilter(new ProxyCallbackFilter(
this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
enhancer.setCallbackTypes(types);

// Generate the proxy class and create a proxy instance.
return createProxyClassAndInstance(enhancer, callbacks);
} // 根据 enhancer 构建代理类 class,然后通过 class 构建代理类实例,最后将 callbacks 设置到其中
catch (CodeGenerationException | IllegalArgumentException ex) {
throw new AopConfigException("Could not generate CGLIB subclass of " + this.advised.getTargetClass() +
": Common causes of this problem include using a final class or a non-visible class",
ex);
}
catch (Throwable ex) {
// TargetSource.getTarget() failed
throw new AopConfigException("Unexpected AOP exception", ex);
}
}

上边的代码就是通过 Enhancer 实例构建代理类的过程,唯一需要注意的就是 Callback[] callbacks = getCallbacks(rootClass); 这行代码,怎么实现的我没管,但是它的返回结果要注意,如下图,可以看到本例中它的长度为 7,且持有了代理工厂和目标类引用,目标类就是我们当前正在处理的 TestBean 实例。

callbacks 数组内容

代理工厂中的内容就更加重要了,可以看到它是持有了我们之前分析得到的全部四个增强信息的。

代理工厂中持有的增强信息

执行到这里我们的代理类创建就完成了,直接回到 AbstractAutoProxyCreator#wrapIfNecessary 方法的 createProxy 这行代码处,接下来它就是缓存了创建的代理类,这样下次获取时就能从缓存中拿,不必重新构建,我们来看看最终得到的代理类内部都有啥信息吧,记下这些信息,后边的代理类方法调用要用上。

构建的代理类内部字段信息

再总结一下代理类的构建过程,在构建我们在 spring 配置文件中指定的 TestBean 时,实现了 BeanPostProcessor 接口的 AspectJAwareAdvisorAutoProxyCreator 实例会对当前构建的 TestBean 进行处理,其规则就是看它是否能够被代理,如果能,就获取匹配当前实例的全部增强,然后根据这些增强及相关信息构建代理类,包括 jdk 和 cglib 两种方式。我们这里使用到的是 cglib 方式,他根本是通过 Enhancer 来构建代理类,最终的代理类是持有了我们获取的全部增强的,在调用代理的的对应方法时,相应的增强会按照一定的顺序执行,这是我们下一部分要说的内容。

代理类方法的执行

经过上文的分析,我们可以知道在主函数中获取到的 TestBean 其实是通过 cglib 构建出来的代理类,这个类的内部如上图所示有 7 个 CALLBACK 字段,如果我们调用该代理类的用户方法,就像测试代码中调用的 test 方法,那么就会触发第一个字段对应的 interceptor 实例的 intercept 方法,因为我 debug 就是进入了该实例的 intercept 方法,所以代理类方法的执行流程就是从该方法开始的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
Object target = null;
TargetSource targetSource = this.advised.getTargetSource();
try {
if (this.advised.exposeProxy) {
// Make invocation available if necessary.
oldProxy = AopContext.setCurrentProxy(proxy); // 如果要暴露代理类,那么就将代理类保存到 AopContext
setProxyContext = true;
}
// Get as late as possible to minimize the time we "own" the target, in case it comes from a pool...
target = targetSource.getTarget();
Class<?> targetClass = (target != null ? target.getClass() : null);
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
Object retVal; // 尝试从缓存中获取 interceptorList,没有的话就从当前实例中获取(获取 Advised 的全部 advisors,看 advisor 是否适配当前方法,适配的话从 advisor 中获取到 Advice,然后将其添加到 interceptorList 集合返回)
// Check whether we only have one InvokerInterceptor: that is,
// no real advice, but just reflective invocation of the target.
if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
// We can skip creating a MethodInvocation: just invoke the target directly.
// Note that the final invoker must be an InvokerInterceptor, so we know
// it does nothing but a reflective operation on the target, and no hot
// swapping or fancy proxying.
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = methodProxy.invoke(target, argsToUse); // 这里是没有拦截器的方法调用方式
}
else {
// We need to create a method invocation... // 将代理相关的参数构建为 CglibMethodInvocation,进行处理,也就是说通过 CglibMethodInvocation 来触发 advice 的调用
retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
}
retVal = processReturnType(proxy, target, method, retVal);
return retVal;
}
finally {
if (target != null && !targetSource.isStatic()) {
targetSource.releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
AopContext.setCurrentProxy(oldProxy);
}
}
}

入口方法如上,这里需要注意的就两点,首先会有一个 if (this.advised.exposeProxy) 的判断,就拿我们的第二个测试用例来说,我们配置了 expose-proxy="true" 属性,那么这个判断条件就会为真,那么程序就会将 proxy 代理类保存到 AopContext 中,这也就是我们能够在测试代码中从 AopContext 拿到代理类的原因。其次是 List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass); 这一行代码,它会尝试从缓存中获取 interceptorList,没有的话就从代理工厂即 advised 中获取,过程比较繁琐,不用去细究,只给出获取的结果如下图就行,一共是四个,正好和上文中分析出来的四个增强相对应。

advice 链图

接下来就是构建 CglibMethodInvocation 实例,它持有了很多关键的信息,从构造函数的参数就可以知道有代理类、目标 bean、目标方法、目标类型、上边得到的四个 advice、以及代理方法。构建的这个 CglibMethodInvocation 它有一个重要的功能就是控制 advice 的调用,我们直接看接下来的 proceed 方法就知道了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public Object proceed() throws Throwable {
// We start with an index of -1 and increment early.
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint(); // 这里就是触发连接点方法
}

Object interceptorOrInterceptionAdvice = // 逐个获取 interceptorOrInterceptionAdvice
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
// Evaluate dynamic method matcher here: static part will already have
// been evaluated and found to match.
InterceptorAndDynamicMethodMatcher dm =
(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
return dm.interceptor.invoke(this);
}
else {
// Dynamic matching failed.
// Skip this interceptor and invoke the next in the chain.
return proceed();
}
}
else {
// It's an interceptor, so we just invoke it: The pointcut will have
// been evaluated statically before this object was constructed. // 对逐个获取的 interceptorOrInterceptionAdvice 进行 invoke 调用
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this); // 参数为通过代理各项参数构建的 CglibMethodInvocation
}
}

这个方法中的 interceptorsAndDynamicMethodMatchers 就是构造函数中传进去的四个 advice,这个方法通过 currentInterceptorIndex 来决定进行哪个 advice 的调用。默认是从第一个 advice 开始的,也就是直接调用它的 invoke 方法,从上文知道,第一个 advice 是 ExposeInvocationInterceptor 实例,它的核心就只是将 CglibMethodInvocation 实例保存到线程本地变量中,执行完这步就是继续调用 CglibMethodInvocation 的 proceed 方法,下边就是 ExposeInvocationInterceptor#invoke 方法的实现。

1
2
3
4
5
6
7
8
9
10
11
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
MethodInvocation oldInvocation = invocation.get();
invocation.set(mi);
try {
return mi.proceed(); // 继续下一个 advice 的调用
}
finally {
invocation.set(oldInvocation);
}
}

调用 CglibMethodInvocation 的 proceed 方法后,就会继续下一个 advice 的方法的调用,这时 currentInterceptorIndex 已经变为 1 了,根据上图,我们可以知道现在拿到的就是 AspectJAfterAdvice 实例,看他的 invoke 方法实现如下,其实现在已经可以猜想出来 AspectJAfterAdvice 代表的增强是在最后执行的,因为它是在 finally 中执行的调用逻辑,而调用 finally 代码块之前只是交由 CglibMethodInvocation 的 proceed 方法,继续下一个 advice 的调用。

1
2
3
4
5
6
7
8
9
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
try {
return mi.proceed();
}
finally {
invokeAdviceMethod(getJoinPointMatch(), null, null);
}
}

这时 currentInterceptorIndex 变为 2,根据上图的信息知道现在将会进行 AspectJAroundAdvice 的 invoke 调用,它的实现如下,关键就是最后一行代码,它的实现我也贴在了下边,根本还是调用了 invokeAdviceMethodWithGivenArgs 方法,在该方法中,argBinding 方法对参数进行了一系列处理,这也不是关注的重点,因为我们现在只是想知道方法具体是怎样调用的,那就直接看
invokeAdviceMethodWithGivenArgs 方法实现。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
if (!(mi instanceof ProxyMethodInvocation)) {
throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi);
}
ProxyMethodInvocation pmi = (ProxyMethodInvocation) mi;
ProceedingJoinPoint pjp = lazyGetProceedingJoinPoint(pmi);
JoinPointMatch jpm = getJoinPointMatch(pmi);
return invokeAdviceMethod(pjp, jpm, null, null);
}

// As above, but in this case we are given the join point.
protected Object invokeAdviceMethod(JoinPoint jp, @Nullable JoinPointMatch jpMatch,
@Nullable Object returnValue, @Nullable Throwable t) throws Throwable {

return invokeAdviceMethodWithGivenArgs(argBinding(jp, jpMatch, returnValue, t));
}

下边就是 invokeAdviceMethodWithGivenArgs 方法的实现,注意根据调用链的关系,我们知道现在是在调用 AspectJAroundAdvice 实例的方法。在该方法中 ,我们根本是调用了 aspectJAdviceMethod 的 invoke 方法,此 aspectJAdviceMethod 是 jdk 原生 Method 类的实例,我们调用它的 invoke 方法,就会触发它所对应实例方法的调用,那么它代表的什么实例方法呢?通过下图的 debug 结果便很清楚了,其实就是我们切面类的 @Around 增强对应的那个方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
protected Object invokeAdviceMethodWithGivenArgs(Object[] args) throws Throwable {
Object[] actualArgs = args;
if (this.aspectJAdviceMethod.getParameterCount() == 0) {
actualArgs = null;
}
try {
ReflectionUtils.makeAccessible(this.aspectJAdviceMethod);
// TODO AopUtils.invokeJoinpointUsingReflection
return this.aspectJAdviceMethod.invoke(this.aspectInstanceFactory.getAspectInstance(), actualArgs); // 这里就是触发真正的增强方法的调用
}
catch (IllegalArgumentException ex) {
throw new AopInvocationException("Mismatch on arguments to advice method [" +
this.aspectJAdviceMethod + "]; pointcut expression [" +
this.pointcut.getPointcutExpression() + "]", ex);
}
catch (InvocationTargetException ex) {
throw ex.getTargetException();
}
}

另外要注意这里的调用传入了参数 actualArgs,他就是上边 argBinding 方法拼凑出来的结果,里边的内容主要的就是一个 CglibMethodInvocation 实例,它持有了我们代理相关的大部分信息,如下图所示。

CglibMethodInvocation 实例信息

知道这些后,我们就直接转到切面类的 AspectJBean#aroundTest 方法中,不用多说控制台就会首先打印我们开篇测试代码的第二条语句了。接着调用参数的 proceed 方法如下,这里的 methodInvocation 刚好就是我上边说的 CglibMethodInvocation 实例,它持有了我们代理相关的大部分信息,同时 advice 的顺序调用也是由他控制的。

1
2
3
4
@Override
public Object proceed() throws Throwable {
return this.methodInvocation.invocableClone().proceed();
}

通过前边的分析,我们知道现在的 currentInterceptorIndex 将会变为 3,这样我们获取到的就是最后一个 advice 了,也就是 MethodBeforeAdviceInterceptor 实例,这一点通过上边的 advice 链图就能知道了,它就持有了一个 AspectJMethodBeforeAdvice 实例,在 MethodBeforeAdviceInterceptor 的 invoke 方法中就是调用了 AspectJMethodBeforeAdvice 的 before 方法如下,而这个 before 方法最终就是调用的 AspectJMethodBeforeAdvice 实例持有的一个 jdk 原生 Method 实例的 invoke 方法,该实例对应的就是切面类中 @Before 注解对应的那个实例方法,所以对其进行调用,就会触发切面类中 AspectJBean#beforeTest 方法的调用,这样我们控制台就会打印 “beforeTest” 字符串了。

org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor#invoke

1
2
3
4
5
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
return mi.proceed();
}

上边的 before 方法执行完成后就会继续调用 mi.proceed(); 方法,这时 currentInterceptorIndex 值满足 ReflectiveMethodInvocation#proceed 方法的第一个 if 条件,就会执行 ReflectiveMethodInvocation#invokeJoinpoint 方法,它会触发目标方法的执行,这个的执行过程比较特殊,我没太看懂,但是 debug 执行的结果就是会跳转到 TestBean#test 方法中去,这也就是我们的目标方法,执行完后,控制台打印出我们预期的几行字符。

好了再回到上一个调用点即 AspectJBean#aroundTest 方法的 o = p.proceed(); 处,继续往下走很清楚控制台将会打印 “aroundAfter” 字符串了,这一点很清楚,那么继续回退,也就是退到 AspectJAfterAdvice#invoke 方法处,这里还有一个 finally 方法没有执行呢,该方法就和 before 方法的执行一样,根本就是调用 jdk 原生 Method 实例的 invoke 方法,而它对应的就是切面类的 AspectJBean#afterTest 方法,这样控制台就会打印 “afterTest” 字符串。

执行到这里,整个的代理方法调用过程算是完成了,总结一下,代理类有七个 CALLBACK 字段,当我们进行目标方法的调用时,代理类实际是调用的第一个 CALLBACK 字段的方法,它对应的是 DynamicAdvisedInterceptor#intercept 方法,我们通过在 DynamicAdvisedInterceptor#intercept 方法中构建 CglibMethodInvocation 实例来控制 advice 链的调用,这样构建代理类时填充进去的增强就会按照一定的顺序在目标方法的前后先后执行。这就是 aop 的实现原理,当然这里是以 cglib 为例进行说明,jdk 代理的方式还请自行分析。