Spring Core Middleware 源码分析二:Spring AOP 之 @AspectJ

Reference

前言

本文作者试图从 Spring AOP 的执行流程上,通过源码分析的角度去弄清楚 Spring 容器内部是如何通过@AspectJ通过使用接口的方式来实现 AOP 的;

本文为作者的原创作品,转载需注明出处;

源码分析

测试用例

继续沿用Spring Core Container 源码分析六:@Service 中使用的测试用例,为了能够测试 Spring AOP 的特性,这里需要做如下的改动,

  • 为 DogService 添加接口;
    增加接口 DogService.java,实现类 DogServiceImpl.java;目的是实现基于接口的 AOP 实现方式;
  • 为 DogService 的方法添加 AOP,DogServiceAspect.java;

DogService.java

1
2
3
4
5
6
7
8
9
10
11
12
13
package org.shangyang.spring.container;

/**
*
* @author shangyang
*
*/
public interface DogService {


public void walkDog(Dog dog);

}

DogServiceImpl.java

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
package org.shangyang.spring.container;

import org.springframework.stereotype.Service;

/**
*
* 专门为狗狗设计的服务,
*
* @author shangyang
*
*/
@Service("dogService")
public class DogServiceImpl implements DogService{

/**
* 提供遛狗服务
*
* @param dog
*/
public void walkDog(Dog dog){

System.out.println("walks the dog "+dog.getName());

}

}

DogServiceAspect.java

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
package org.shangyang.spring.container;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

/**
*
* @author shangyang
*
*/
@Aspect
@Component
public class DogServiceAspect {

/**
* 拦截方法 @See {@link DogService#walkDog(Dog)} 方法并实现 around advice AOP;
*
* @param pjp
* @return
* @throws Throwable
*/
@Around("execution(* org.shangyang.spring.container.DogServiceImpl.walkDog(..))")
public Object aroundWalkService(ProceedingJoinPoint pjp) throws Throwable {

System.out.println("before around aspect ~~");

Object retVal = pjp.proceed();

System.out.println("after around aspect ~~ ");

return retVal;

}

}

当 Spring 容器解析到带有注解 @Aspect 的 Spring bean DogServiceAspect 的时候,与其 pointcut expression 相匹配的 beans 会通过 auto-proxing 技术自动的为其生成代理对象,并注入 Spring 容器中;

beans.xml

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
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">

<context:component-scan base-package="org.shangyang" />

<aop:aspectj-autoproxy/>

<bean name="john" class="org.shangyang.spring.container.Person">
<property name="name" value="John Doe"/>
<property name="spouse" ref="jane"/>
</bean>

<bean name="jane" class="org.shangyang.spring.container.Person">
<property name="name" value="Jane Doe"/>
</bean>

<bean name="niba" class="org.shangyang.spring.container.Dog">
<property name="name" value="Niba" />
</bean>

</beans>

注意,要启动 @Aspectj auto-proxing 的 AOP 的方式,需要使用到 <aop:aspectj-autoproxy>

执行测试

1
2
3
4
5
6
7
8
9
10
11
@Test
public void testApplicationContext(){

@SuppressWarnings("resource")
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");

Person p = context.getBean("john", Person.class);

p.walksDog();

}

1
2
3
before around aspect ~~
walks the dog Niba
after around aspect ~~

可见,通过 AOP 在方法 DogService#walkDog(Dog) 的方法调用前后成功的织入了 DogServiceAspect#aroundWalkService 中的逻辑;

Advice、Advisor 和 Advised

有关 Advice、Advisor 和 Advised 的讲解参看【12.8】 Manipulating advised objects,在该章节的第二个有旗标处,作者做了一个总结和分类;总体而言,

  • Advice
    Advice 提供了对 join point 的 before、after 和 around 等的方法调用实现
  • Advisor
    在 Advice 上更进一步,Advice 在 join point 上定义了行为,而 Advisor 在此基础上通过 pointcut 定义了该行为怎么发生,什么时候发生
  • Advised
    Advised 接口,从命名上就非常清晰的体现了它的作用,已经被 Advice 之后的对象,叫做 Advised;从类的注解上可以清晰的看到,该接口对象保存了被代理对象(proxied object)的相关配置属性等

流程分析

分析思路及总纲

要弄清楚基于 @AspectJ 的 Spring AOP 的代理实现,需要从四个方面入手,

  1. bean definition <aop:aspectj-autoproxy/> 是如何被解析的?
    该部分参考 aop:aspectj-autoproxy element 章节;其核心作用就是去注册AnnotationAwareAspectJAutoProxyCreator相关联的 post-bean-process definition

  2. @Aspect DogServiceAspect (AspectJ-annoated bean) 是如何被解析成 Advisor 并被注入 Spring 容器中的?
    该部分参考解析并注册 @Aspect DogServiceAspect 到 Spring 容器小节;

  3. DogService 是如何根据 Adviosr 的相关描述生成代理 Proxy 的?
    该部分参考生成 bean 的代理对象 Proxy 并注册

  4. 执行 DogService 的代理对象;

aop:aspectj-autoproxy element

要让容器能够支持 @AspectJ 注解的方式,<aop:aspectj-autoproxy/> 配置是必须的,那么,本小节将会分析,该配置元素在 Spring 容器的初始化过程是如何被解析的并起到了什么样的作用?

Spring Core Container 源码分析七:注册 Bean Definitions 中我们知道,当解析到一些特殊的自定义的元素(比如 <context:component-scan/>等元素)的时候,会进入 parse custom element process 流程;再来看看当时针对 custom element <context:component-scan/> 的有关的详细分析流程,

这里的区别是,custom element 换成了 <aop:aspectj-autoproxy/> 那么对应上述的流程变化有,

综上所述,配置元素 <aop:aspectj-autoproxy/> 的作用就是去注册AnnotationAwareAspectJAutoProxyCreator相关联的 post-bean-process definition;

parse element by AopNamespaceHandler

这部分不复杂,主要就是去注册 AnnotationAwareAspectJAutoProxyCreator post-bean-process definition;不画流程图了,直接看源码,

AopNamespaceHandler.parse(element, parserContext) -> AspectJAutoProxyBeanDefinitionParser.parse(element, parserContext)

AspectJAutoProxyBeanDefinitionParser.java

1
2
3
4
5
6
7
@Override
public BeanDefinition parse(Element element, ParserContext parserContext) {
// 这一步主要是去注册 AnnotationAwareAspectJAutoProxyCreator post-bean-process definition;
AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element);
extendBeanDefinition(element, parserContext);
return null;
}

AopNamespaceUtils.java

1
2
3
4
5
6
7
8
9
10
public static void registerAspectJAnnotationAutoProxyCreatorIfNecessary(
ParserContext parserContext, Element sourceElement) {

// register AspectJAnnotationAutoProxyCreator
BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(
parserContext.getRegistry(), parserContext.extractSource(sourceElement));
// 去判断是否用户强制使用了 CGLIB 的 Class Proxing 的模式;
useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
registerComponentIfNecessary(beanDefinition, parserContext);
}

主要逻辑在第一个方法 registerAspectJAnnotationAutoProxyCreatorIfNecessary,内部逻辑就是以名字 org.springframework.aop.config.internalAutoProxyCreator 来注册AnnotationAwareAspectJAutoProxyCreator所对应的 post-bean-process definition;最后注册到当前的 Spring 容器中;相关核心逻辑如下,

1
2
3
4
5
6
7
8
9
10
11
12
private static BeanDefinition registerOrEscalateApcAsRequired(Class<?> cls, BeanDefinitionRegistry registry, Object source) {

......

RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
beanDefinition.setSource(source);
beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
// 以名字 org.springframework.aop.config.internalAutoProxyCreator 来注册 AnnotationAwareAspectJAutoProxyCreator 所对应的 bean definition
registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
return beanDefinition;
}

解析 @Aspect class 生成 Advisor 对象并注册

该小节描述,如何将 @AspectJ 对象(DogServiceAspect)转换成相应的 Advisor 对象并注册到容器中;

该过程涉及到 AnnotationAwareAspectJAutoProxyCreator 作为 InstantiationAwareBeanPostProcessor 的回调过程;见 Do Get Bean 流程

解析并注册 @Aspect DogServiceAspect 主要发生在 step 1.3.1.1.1 resolveBeforeInstantiation 过程中,主要是回调了 InstantiationAwareBeanPostProcessorpostProcessBeforeInitialization 方法

直接看源码来一步一步的进行分析,

DefaultListableBeanFactory(AbstractAutowireCapableBeanFactory).java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
Object bean = null;
if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
// Make sure bean class is actually resolved at this point.
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
Class<?> targetType = determineTargetType(beanName, mbd);
if (targetType != null) {
bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
if (bean != null) {
bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
}
}
}
mbd.beforeInstantiationResolved = (bean != null);
}
return bean;
}

代码第 8 行,applyBeanPostProcessorsBeforeInstantiation 该方法主要是去回调 InstantiationAwareBeanPostProcessor 的 postProcessBeforeInitialization 方法;那么就该方法继续进行深挖,

1
2
3
4
5
6
7
8
9
10
11
12
protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);
if (result != null) {
return result;
}
}
}
return null;
}

AnnotationAwareAspectJAutoProxyCreator(AbstractAutoProxyCreator).postProcessBeforeInstantiation

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
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
Object cacheKey = getCacheKey(beanClass, beanName);

if (beanName == null || !this.targetSourcedBeans.contains(beanName)) {
if (this.advisedBeans.containsKey(cacheKey)) {
return null;
}
if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return null;
}
}

// 下面这段代码可以忽略不计,它主要是去处理 TargetSource 相关逻辑的;
// Create proxy here if we have a custom TargetSource.
// Suppresses unnecessary default instantiation of the target bean:
// The TargetSource will handle target instances in a custom fashion.
if (beanName != null) {
TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
if (targetSource != null) {
this.targetSourcedBeans.add(beanName);
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
}

return null;
}

这个回调方法重要了,但是,让人跌眼镜的是,你万万不会想到最关键且最核心的地方是在代码第 9 行,不去 debug 真不知道,解析并注册 @Aspect DogServiceAspect 到 Spring 容器的逻辑是在 shouldSkip 判断方法中实现的,

1
if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName))

好吧,我们就进一步看看 shouldSkip 为什么这么妖艳…

AnnotationAwareAspectJAutoProxyCreator(AspectJAwareAdvisorAutoProxyCreator).shouldSkip

1
2
3
4
5
6
7
8
9
10
11
12
13
@Override
protected boolean shouldSkip(Class<?> beanClass, String beanName) {
// TODO: Consider optimization by caching the list of the aspect names
List<Advisor> candidateAdvisors = findCandidateAdvisors();
for (Advisor advisor : candidateAdvisors) {
if (advisor instanceof AspectJPointcutAdvisor) {
if (((AbstractAspectJAdvice) advisor.getAdvice()).getAspectName().equals(beanName)) {
return true;
}
}
}
return super.shouldSkip(beanClass, beanName);
}

好了,最关键的代码出现了,代码第 4 行 findCandidateAdvisors();,为了体现其重要性,单独创建一个小节 find candidate advisors 来进行描述;

find candidate advisors

接上述代码分析的内容;

AnnotationAwareAspectJAutoProxyCreator.java

1
2
3
4
5
6
7
8
@Override
protected List<Advisor> findCandidateAdvisors() {
// Add all the Spring advisors found according to superclass rules.
List<Advisor> advisors = super.findCandidateAdvisors();
// Build Advisors for all AspectJ aspects in the bean factory.
advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
return advisors;
}

最关键的代码在第 6 行,this.aspectJAdvisorsBuilder.buildAspectJAdvisors()

BeanFactoryAspectJAdvisorsBuilder.buildAspectJAdvisors

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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
/**
* Look for AspectJ-annotated aspect beans in the current bean factory,
* and return to a list of Spring AOP Advisors representing them.
* <p>Creates a Spring Advisor for each AspectJ advice method.
* @return the list of {@link org.springframework.aop.Advisor} beans
* @see #isEligibleBean
*/
public List<Advisor> buildAspectJAdvisors() {
List<String> aspectNames = this.aspectBeanNames;

if (aspectNames == null) {
synchronized (this) {
aspectNames = this.aspectBeanNames;
if (aspectNames == null) {

List<Advisor> advisors = new LinkedList<Advisor>();
aspectNames = new LinkedList<String>();

// 这个方法挺狠的,返回了当前容器中所有的 bean names...
String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory, Object.class, true, false);

for (String beanName : beanNames) {
// 是不是 Aspect Bean? 当前用例中的 DogServiceAspect 就是
if (!isEligibleBean(beanName)) {
continue;
}
// We must be careful not to instantiate beans eagerly as in this case they
// would be cached by the Spring container but would not have been weaved.
Class<?> beanType = this.beanFactory.getType(beanName);
if (beanType == null) {
continue;
}
if (this.advisorFactory.isAspect(beanType)) {
aspectNames.add(beanName);
AspectMetadata amd = new AspectMetadata(beanType, beanName);
if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
// 处理 Singleton 的情况;
MetadataAwareAspectInstanceFactory factory =
new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);

....

// 缓存已解析生成的 advisors
this.advisorsCache.put(beanName, classAdvisors);

....

advisors.addAll(classAdvisors);
}
else {
// Per target or per this. 为每个 pointcut 创建一个 aspect 对象
MetadataAwareAspectInstanceFactory factory =
new PrototypeAspectInstanceFactory(this.beanFactory, beanName);
this.aspectFactoryCache.put(beanName, factory);
advisors.addAll(this.advisorFactory.getAdvisors(factory));
}
}
}
this.aspectBeanNames = aspectNames;
return advisors;
}
}
}

......

// 后面这段逻辑是从缓存中直接取 Advisor
List<Advisor> advisors = new LinkedList<Advisor>();
for (String aspectName : aspectNames) {
List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName);
if (cachedAdvisors != null) {
advisors.addAll(cachedAdvisors);
}
else {
MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName);
advisors.addAll(this.advisorFactory.getAdvisors(factory));
}
}
return advisors;
}

这段代码是解析 AspectJ-annotated aspect beans,生成相应的 Advisors,并将 Advisors 注册到容器中整个过程的核心所在,下面依次对其进行解析;

首先,通过 BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.beanFactory, Object.class, true, false) 方法的调用,得到了所有的 bean names;既代码第 20 行;

其次,依次遍历 bean names 依次判断是否为 AspectJ-annotated aspect beans,如果发现是 Aspect-annotated bean( 在我们的测试用例中,对应的就是被 @Aspect 所注解的 DogServiceAspect.java ),那么将会根据 per this 或者 singleton 的情况来分别处理,这里我们只来关注 singleton 的方式,从代码第 37 行开始;随后,代码第 41 行,通过方法 this.advisorFactory.getAdvisors(factory) 解析 AspectJ-annotated bean (DogServiceAspect.java) 并生成与之相关的 Advisor 对象,具体参考小节生成 Advisors

最后,将上述生成的 advisors 缓存到 this.advisorsCache 和 this.aspectBeanNames 中;

生成 Advisors

下面我们就 this.advisorFactory.getAdvisors(factory) 方法进一步分析,

ReflectiveAspectJAdvisorFactory.getAdvisors

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
@Override
public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();
validate(aspectClass);

// We need to wrap the MetadataAwareAspectInstanceFactory with a decorator
// so that it will only instantiate once.
MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);

List<Advisor> advisors = new LinkedList<Advisor>();
for (Method method : getAdvisorMethods(aspectClass)) {
Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, advisors.size(), aspectName);
if (advisor != null) {
advisors.add(advisor);
}
}

// If it's a per target aspect, emit the dummy instantiating aspect.
if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);
advisors.add(0, instantiationAdvisor);
}

// Find introduction fields.
for (Field field : aspectClass.getDeclaredFields()) {
Advisor advisor = getDeclareParentsAdvisor(field);
if (advisor != null) {
advisors.add(advisor);
}
}

return advisors;
}

上述代码中,最主要的部分在代码第 12 到 18 行,该部分代码将会根据 @Aspect 类生成相应的 Advisor 对象,

1
2
3
4
5
6
7
List<Advisor> advisors = new LinkedList<Advisor>();
for (Method method : getAdvisorMethods(aspectClass)) {
Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, advisors.size(), aspectName);
if (advisor != null) {
advisors.add(advisor);
}
}

挨个遍历 aspect class 的 methods,针对每个 method 调用 getAdvisor 方法并判断该 method 上是否注释了 pointcut expression,新生成一个 AspectJExpressionPointcut 实例,并将其封装为一个Advisor对象 InstantiationModelAwarePointcutAdvisorImpl 返回;至此 Advisor 生成;看下这段 getAdvisor 方法调用的源码

ReflectiveAspectJAdvisorFactory.getAdvisor

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Override
public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
int declarationOrderInAspect, String aspectName) {

validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());

AspectJExpressionPointcut expressionPointcut = getPointcut(
candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
if (expressionPointcut == null) {
return null;
}

return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod, this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
}

总结,

该小节主要是遍历所有的 Class 找到 @Aspect class 并生成对应的 Advisor 对象,最后返回;

生成 bean 的代理对象 Proxy 并注册

本小节考察的是,bean 是如何根据 Advisor 相关描述生成其代理对象 Proxy 并注册的?

该部分工作主要是当AnnotationAwareAspectJAutoProxyCreator作为 bean-post-processor 的时候,通过其回调方法 postProcessAfterInitialization 完成的;回顾一下,bean-post-processor 的回调过程,它的接口是在 initialize bean 流程中被回调的,详细步骤参考回调 bean-post-processors 接口方法

我们看看 AnnotationAwareAspectJAutoProxyCreator.postProcessAfterInitialization 方法被回调的内部执行过程;

AnnotationAwareAspectJAutoProxyCreator.java

1
2
3
4
5
6
7
8
9
10
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (!this.earlyProxyReferences.contains(cacheKey)) {
return wrapIfNecessary(bean, beanName, cacheKey); // 判断当前的 bean 是否需要被 wrap 成 proxy;既是被封装为 proxy 对象;
}
}
return bean;
}

主要逻辑发生在代码第 6 行,wrapIfNecessary

AnnotationAwareAspectJAutoProxyCreator.java

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
/**
* 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
*/
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
// 首先排除 Target Source bean..
if (beanName != null && this.targetSourcedBeans.contains(beanName)) {
return bean;
}

// 再次排除已经被 proxied 的 bean
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}

// Spring 容器内置的 beans
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}

// Create proxy if we have advice.
// 通过 Advisor 中配置的 pointcut 与当前的 bean 进行匹配,看是否有与之匹配的方法 Advice,若有,则返回;
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
Object proxy = createProxy(
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}

this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}

核心代码从第 27 行开始,主要做了这么三件事情

  1. 找到与该 bean 相关的 Advisors,代码第 27 行,
    具体实现细节参考找到与 Bean 相关的 Advisors,这里所需要的 Advisor 就是从解析 @Aspect class 生成 Advisor 对象并注册所生成的;

  2. 为当前 bean 生成 Proxy 对象,代码第 30 行,
    这里要特别注意的是,用 SingletonTargetSource 封装了 bean 并用其作为参数来创建 Proxy,具体实现细节参考生成 bean 的代理对象 Proxy;

  3. 缓存 Advised bean,代码第 29 行 和 32 行,

  4. 返回 proxy 对象,代码第 33 行;

总结,通过AnnotationAwareAspectJAutoProxyCreator作为 bean-post-processor 回调其接口方法 postProcessAfterInitialization 完成了对相关 bean 的代理实现,生成其所对应的 Proxy 对象;而后,根据创建 bean 的流程,该 Proxy 将会被注入到 BeanFactory 中;也就意味着,当使用ApplicationContext从容易中根据该 bean name 获取到的 bean 实际上是一个 Proxy 对象;

找到与 Bean 相关的 Advisors

AnnotationAwareAspectJAutoProxyCreator(AbstractAdvisorAutoProxyCreator).java

1
2
3
4
5
6
7
8
@Override
protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, TargetSource targetSource) {
List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
if (advisors.isEmpty()) {
return DO_NOT_PROXY;
}
return advisors.toArray();
}

代码第三行,findEligibleAdvisors

AnnotationAwareAspectJAutoProxyCreator(AbstractAdvisorAutoProxyCreator).java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/**
* Find all eligible Advisors for auto-proxying this class.
* @param beanClass the clazz to find advisors for
* @param beanName the name of the currently proxied bean
* @return the empty List, not {@code null},
* if there are no pointcuts or interceptors
* @see #findCandidateAdvisors
* @see #sortAdvisors
* @see #extendAdvisors
*/
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
// 找到 Spring 容器中的所有的 Advisor;Advisor = Advice + Pointcut;
List<Advisor> candidateAdvisors = findCandidateAdvisors();
// 找到所有能够应用到当前 bean 的 Advisors 对象;
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
extendAdvisors(eligibleAdvisors);
if (!eligibleAdvisors.isEmpty()) {
// 给多个 Advisors 进行排序
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}

  1. 找到当前容器中所有的 Advisors 对象,代码第 13 行;

  2. 然后依次遍历这些 Advisor,并判断其 pointcut expression 是否可以适用于当前的 bean,如果适用,那么就将 Advisor 添加入 eligibleAdvisors;代码第 15 行

  3. 通过 Order 接口对 eligibleAdvisors 进行排序;代码 19 行
    可见,当你有多个适配的 Advisor 对象的时候,Order 接口就显得尤为的重要了;

生成 bean 的代理对象 Proxy

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
/**
* Create an AOP proxy for the given bean.
* @param beanClass the class of the bean
* @param beanName the name of the bean
* @param specificInterceptors the set of interceptors that is
* specific to this bean (may be empty, but not null)
* @param targetSource the TargetSource for the proxy,
* already pre-configured to access the bean
* @return the AOP proxy for the bean
* @see #buildAdvisors
*/
protected Object createProxy(
Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) {

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

ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.copyFrom(this);

if (!proxyFactory.isProxyTargetClass()) {
if (shouldProxyTargetClass(beanClass, beanName)) { // 是否采用 CGLIB
proxyFactory.setProxyTargetClass(true);
}
else { // 采用 Interface 作为代理的方式
// 解析出当前的 bean 的 interfaces,并设置到当前的 proxyFactory 中
evaluateProxyInterfaces(beanClass, proxyFactory);
}
}
// 这里充当 Adapter 的作用,将 Advice 和 MethodInterceptor 封装为 Advisor 对象
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);

for (Advisor advisor : advisors) {
proxyFactory.addAdvisor(advisor);
}

proxyFactory.setTargetSource(targetSource);
customizeProxyFactory(proxyFactory);

// 如果设置为 frozen,那么就不能够对 Advised Object 继续添加 Advisor 了;
proxyFactory.setFrozen(this.freezeProxy);

if (advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true);
}

return proxyFactory.getProxy(getProxyClassLoader()); // 生成 Proxy 并返回
}

上面的代码就是如何通过 bean 和与其相关的 Advisor 通过接口的方式或者是通过 CGLIB 的方式生成其代理对象 Proxy;这里,我们将“主要关注用接口生成代理对象的过程”;

  1. 创建 ProxyFactory 实例,代码 L19
  2. 解析当前 bean 的相关接口,并设置到当前的 ProxyFactory 实例中;L28
    通过如下代码实现

    1
    proxyFactory.addInterface(ifc);
  3. L32,将 Advice 和 MethodInterceptor 统一封装为 Advisors 对象

  4. L34-36,将 Advisors 注入 proxyFactory 中;
  5. L38,设置 target source
  6. L42,设置 Frozen,【12.8】 Manipulating advised objects 有对 frozen 标志的详细描述,frozen 标志设置为 true,那么就不能对 advised 再设置 advisor/advice 了;
  7. L48,通过 ProxyFactory 实例生成当前 bean 的代理;proxyFactory.getProxy(getProxyClassLoader()); 详情参考通过 ProxyFactory 生成 Proxy 代理对象
通过 ProxyFactory 生成 Proxy 代理对象

先来看看 ProxyFactory 的一张类图,可见其对应三个父类,

整个创建 Proxy 的流程图如下,

首先 ProxyFactory 是一个 prototype 对象;主要步骤如下,

  1. step 1.1.1.1,将 proxyFactory 作为其构造参数创建 JdkDynamicAopProxy 对象,要注意的是,step 1.1.1.1.1 将 proxyFactory 参数赋值给了 this.advised;JdkDynamicProxy 对象非常的关键,里面提供了 InvocationHandler.invoke 回调方法的实现;

  2. step 1.1.2.2,调用 java.lang.reflection.Proxy 的方法 newProxyInstance 创建一个 Proxy 实例,需要注意的有,
    参数 proxiedInterfaces:这里不仅仅包含了 DogService 接口,同时包含了 SpringProxy、Advised 以及 DecoratingProxy 接口;这里为什么要提供这些额外的接口,以 Advised 接口为例,为了提供 Proxy 对象相关的 Advice、Interceptors 以及 Advisors 信息等等;至于 java 如何通过 java.lang.reflection.Proxy 创建生成的 Proxy 代理对象,将来打算专门写一个博文来深入分析;

看看 step 1.1.2 getProxy 的源码,

JdkDynamicAopProxy.java

1
2
3
4
5
6
7
8
9
10
11
12
@Override
public Object getProxy(ClassLoader classLoader) {
if (logger.isDebugEnabled()) {
logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());
}
// 除了当前 bean 的接口 DogService 外,还返回了
// org.springframework.aop.SpringProxy, org.springframework.aop.framework.Advised, org.springframework.core.DecoratingProxy
// 目的就是让返回的代理对象 Proxy 不仅仅是当前 bean 的代理,而且还包含了其它额外重要的信息,比如 @see Advised、SpringProxy 以及 DecoratingProxy 等信息;
Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this); // 生成代理对象
}

执行 Proxy 方法调用的内部逻辑

该小节主要是从源码的层面来分析在 Spring 容器中是如何通过 DogServiceImpl 的 Proxy 对象来进行调用的,为了清晰的看到整个调用过程,我们将测试用例的相关源码再次粘贴如下,

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
package org.shangyang.spring.container;

import org.springframework.beans.factory.annotation.Autowired;

/**
*
* @author shangyang
*
*/
public class Person {

String name;

Person spouse;

@Autowired
Dog dog;

@Autowired
DogService dogService;

.....

// walks my dog
public void walksDog(){
dogService.walkDog(dog);
}

}

通过前面的小节生成 bean 的代理对象 Proxy 并注册的分析可知,这里通过 @Autowired 得到的 DogService 是通过生成 bean 的代理对象 Proxy步骤对 DogServiceImpl 生成的代理对象 proxy;所以在 Person.walksDog 方法中所调用的 dogService.walksDog(dog) 是调用的是 DogService 接口的代理实现类 proxy 的 walksDog(dog) 方法;来看有关该 Proxy 的调用流程图,

内部逻辑实在是很复杂,数度想放弃该流程图的制作,但是,最终顽强的毅力还是让我坚持下来了;既然很复杂,又要在这个小节内对其主要功能和流程描述清楚,那么自然就不能过多的涉及相关细节的讲解,将来考虑专门从 Spring AOP 的框架层面,从顶层接口 Advice、Advisor、MethodInterceptor、AopProxy、ReflectiveMethodInvocation 等对象详细深入的剖析 Spring AOP 的内部逻辑;

主要流程已经由红色箭头标注出来了,

  1. step 2.1 dogService.walkDog 开始了关于 dogServiceImpl 的 proxy 的调用过程
    注意,该步骤中的调用对象 dogService 是注入 Person 实例中的 $Proxy 实例;

  2. step 2.1.1 紧接着调用 JdkDynamicAopProxy (Spring AOP 中所封装的 InvocationHandler 对象) 的 invoke 方法,从流程图通过 ProxyFactory 生成 Proxy 代理对象中我们可以看到对象 JdkDynamicAopProxy 是如何被初始化出来的,要特别注意的是,该对象保存了 ProxyFactory 实例;

  3. step 2.1.1.6 初始化 ReflectiveMethodInvocation 实例 invocation,并且将一系列重要的参数 proxy、target、method、args 等保存在该实例中

  4. step 2.1.1.7 调用 ReflectiveMethodInvocation 实例的 proceed 方法,
    里面要注意的是, step 2.1.1.7.1 按照 advices 的优先顺序取得了第一个待执行的 advice

  5. step 2.1.1.7.2 开始进行 advice 的相关调用,

    step 2.1.1.7.2.3.1 argBinding 该方法是将 args 与 advice 的参数进行匹配并绑定;

    step 2.1.1.7.2.3.2.2 adviceMethod.invoke(dogServiceAspect, args:Object[]) 方法开始调用 Aspect 的拦截方法 dogServiceAdvice.aroundWalkService(pjp:ProceedingJoinPoint);该过程要注意的是,args 参数 Object[] 数组中的第一个参数既是 dogServiceAdvice 所需要的 pjp:ProceedingJoinPoint 参数;

    step 2.1.1.7.2.3.2.2.1.1 advice before invocation 开始调用 Around Advice 的 before 切入逻辑;

    step 2.1.1.7.2.3.2.2.1.2.1 this.methodInvocation.proceed 该方法进入对 Target 被代理对象 DogServiceImpl 的调用,step 2.1.1.7.2.3.2.2.1.2.1.1.1.1 walkDog(dog) 通过方法的反射调用原生对象 DogServiceImpl 的方法 walkDog(dog);

    这里要重点关注的是 step 2.1.1.7.2.3.2.2.1.2.1.1.2 重复 2.1.1.7.1 的步骤,继续处理 Advices,正如我在流程图中的备注那样,如果有多个 Advices,在这里就会发生递归调用,也就是通过此递归调用的方式直到将所有的 Advices 处理干净;

    step 2.1.1.7.2.3.2.2.1.3 advice after invocation 调用 Around Advice 的 after 切入逻辑;

上面调用的大致流程梳理清楚了,总而言之,通过 InvocationHandler JdkDynamicAopProxy 对象开始了对 Advices 方法的调用,处理 Advices 的过程是采用递归调用逐一处理的方式,直到将 before Advices 处理完毕以后,对 Target 进行调用,然后通过递归出栈的过程,逐一调用 Advice after 的逻辑;总体而言,Spring AOP 借助于 Advice 的拦截方法实现用户的织入逻辑;

补充

AnnotationAwareAspectJAutoProxyCreator

aop:aspectj-autoproxy element 小节中,我们知道了AnnotationAwareAspectJAutoProxyCreator对象;下面对该对象进行简要的分析,

可见,其主要实现了 BeanPostProcessor 接口以及两个与其相关的子接口 InstantiationAwareBeanPostProcessor 和 SmartInstantiationAwareBeanPostProcessor;当作为 InstantiationAwareBeanPostProcessor 的时候,其产生的作用参考解析 @Aspect class 生成 Advisor 对象并注册;当作为 BeanPostProcessor 的时候,其产生的作用参考生成 bean 的代理对象 Proxy 并注册

思维导图

<aop:aspectj-autoproxy> -> AnnotationAwareAspectJAutoProxyCreator bean-post-processor

@AspectJ -> Advisor -> Advice

@Proxy ->

TODO, 画一张思维导图来总结各个节点之间的关联关系;