dcddc

西米大人的博客

0%

系统学习Spring源码-aop

前言

为了避免一些公共代码每次都要在 bean 里单独添加,提出了 aop 的解决方案,使用面向切面编程的思想,统一处理 bean 中与业务逻辑无关的公共代码

注册 APC 的 BD

xml 方式

xml 方式通过配置<aop:aspectj-autoproxy/>启用 AOP,在 bean 注册里介绍过,这属于 Spring 的自定义标签,命名空间是 aop,标签是 aspectj-autoproxy。Spring 会通过 aop 命名空间 Handler:AopNamespaceHandler,获取 aspectj-autoproxy 标签的解析器AspectJAutoProxyBeanDefinitionParser,执行 parse 方法解析标签,调用方法AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary注册自动代理创建器(APC)的 bd 到 beanFactory

  • 这里注册的 APC 是AnnotationAwareAspectJAutoProxyCreator
    • 它是一个 SmartInstantiationAwareBeanPostProcessor,Spring 容器初始化阶段加载并注册到 beanFactory
  • Spring 定义了三个自动代理 APC,如果还注册了其他的 APC,根据优先级来决定最终注册哪个 APC 的 bd 到 beanFactory。不同的 APC,创建 aop 代理的过程有所差异
    • 优先级:AnnotationAwareAspectJAutoProxyCreator > AspectJAwareAdvisorAutoProxyCreator > InfrastructureAdvisorAutoProxyCreator
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
public BeanDefinition parse(Element element, ParserContext parserContext) {
// 主要是注册APC的bd到beanFactory
AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element);
extendBeanDefinition(element, parserContext);
return null;
}

public static void registerAspectJAnnotationAutoProxyCreatorIfNecessary(
ParserContext parserContext, Element sourceElement) {

// 注册自动代理创建器APC的bd到beanFactory
BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(
parserContext.getRegistry(), parserContext.extractSource(sourceElement));
// APC的bd增加一些自定义逻辑控制属性,包括是否强制使用CGLIB代理、是否暴露代理类给用户使用
useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
registerComponentIfNecessary(beanDefinition, parserContext);
}

public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(
BeanDefinitionRegistry registry, @Nullable Object source) {

return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
}

private static BeanDefinition registerOrEscalateApcAsRequired(
Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {

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

// 如果已存在APC(自动代理创建器)的bd,按APC优先级决定最终使用的APC
if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
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);
registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
return beanDefinition;
}

private static int findPriorityForClass(@Nullable String className) {
for (int i = 0; i < APC_PRIORITY_LIST.size(); i++) {
Class<?> clazz = APC_PRIORITY_LIST.get(i);
if (clazz.getName().equals(className)) {
return i;
}
}
... ...
}

private static final List<Class<?>> APC_PRIORITY_LIST = new ArrayList<>(3);

static {
// Set up the escalation list...
APC_PRIORITY_LIST.add(InfrastructureAdvisorAutoProxyCreator.class);
APC_PRIORITY_LIST.add(AspectJAwareAdvisorAutoProxyCreator.class);
APC_PRIORITY_LIST.add(AnnotationAwareAspectJAutoProxyCreator.class);
}

APC 的 bd.pv 增加一些逻辑控制属性

  • 是否强制使用 CGLIB 代理
    • 如果 aspectj-autoproxy 标签的 proxy-target-class 属性为 true,强制使用 CGLIB 为目标对象创建代理
    • CGLIB 是在运行期依赖 ASM 操作字节码生成目标类的子类来实现代理,能代理除 final 方法(不能被 override)外的所有方法,且性能更好
    • JDK 动态代理是 Spring 默认使用的动态代理,在运行期创建接口实现类来代理目标类,因此只能代理接口方法
  • 是否支持暴露代理类
    • 如果 aspectj-autoproxy 标签的 expose-proxy 属性为 true,支持暴露代理类
      • 目的是解决某些场景下无法代理方法的问题:例如被代理类方法 a 内部又调用了它的另一个方法 b,该方法 b 的调用是无法被代理的,需要显式调用 AopContext.currentProxy 获取代理类来调用方法 b
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
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);
}
}
}

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);
}
}

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);
}
}

注解方式

注解方式开启 aop 需要使用注解:@EnableAspectJAutoProxy。它会 import 一个 bd 注册器:AspectJAutoProxyRegistrar,由它向 bf 注册 apc。和 xml 方式本质一样,都会通过调用方法AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary来注册 apc。然后读取@EnableAspectJAutoProxy 注解的属性,填充到注册的 apc 的 bd

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {

/**
* Register, escalate, and configure the AspectJ auto proxy creator based on the value
* of the @{@link EnableAspectJAutoProxy#proxyTargetClass()} attribute on the importing
* {@code @Configuration} class.
*/
@Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {

AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);

AnnotationAttributes enableAspectJAutoProxy = AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
if (enableAspectJAutoProxy != null) {
if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
}
if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
}
}
}

}

APC 创建 bean 代理类

通过上面的分析,使用<aop:aspectj-autoproxy/>@EnableAspectJAutoProxy启用 AOP,默认使用的 APC 就是AnnotationAwareAspectJAutoProxyCreator,它是一个 bpp:SmartInstantiationAwareBeanPostProcessor,在 bean 加载过程中完成对目标 bean 的代理。
其实所有的 APC 都是 bpp:SmartInstantiationAwareBeanPostProcessor,基于 bpp 的回调钩子来为 bean 创建 aop 代理。

1
2
public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware {}

下面会介绍 APC 在 bean 加载过程中如何为 bean 创建 aop 代理类。在分析源码前,先说一下预备知识:

  • aop 模块的核心 bean 是Advisor增强容器,它包括增强器Advice和切点Pointcut。增强器 Advice 实现具体的增强逻辑,切点 PointCut 用于判断是否与 bean 方法匹配,只有匹配上的 bean 才会被 aop 代理
    • Advisor其实只包含Advice,它的子类PointcutAdvisor引入了Pointcut,所以增强容器真正指的是PointcutAdvisor,下文不区分AdvisorPointcutAdvisor

bean 前置实例化处理

入口:org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#postProcessBeforeInstantiation

bean 前置实例化处理主要做了两件事:

  • 缓存不需要被代理增强的 bean
    • 用于做 aop 代理的 bean,包括 Advisor、Advice、Pointcut 的实现类
    • 使用@Aspect 修饰的切面类
  • 加载并筛选所有 advisor bean
    • 特别的,AnnotationAwareAspectJAutoProxyCreator 会为@Aspect 切面类中每个增强方法创建增强容器 advisor
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
if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
// 缓存无需增强代理的bean
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return null;
}

protected boolean isInfrastructureClass(Class<?> beanClass) {
boolean retVal = Advice.class.isAssignableFrom(beanClass) ||
Pointcut.class.isAssignableFrom(beanClass) ||
Advisor.class.isAssignableFrom(beanClass) ||
AopInfrastructureBean.class.isAssignableFrom(beanClass);
return retVal || hasAspectAnnotation(beanClass);
}

private boolean hasAspectAnnotation(Class<?> clazz) {
return (AnnotationUtils.findAnnotation(clazz, Aspect.class) != null);
}

protected boolean shouldSkip(Class<?> beanClass, String beanName) {
List<Advisor> candidateAdvisors = findCandidateAdvisors();
for (Advisor advisor : candidateAdvisors) {
if (advisor instanceof AspectJPointcutAdvisor &&
((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName)) {
return true;
}
}
return super.shouldSkip(beanClass, beanName);
}

findCandidateAdvisors 是 aop 的核心方法,它会返回当前 APC 下的所有候选 advisor。AbstractAdvisorAutoProxyCreator里首次定义并给出了基础实现,它会加载所有 Advisor bean

AnnotationAwareAspectJAutoProxyCreator继承AbstractAdvisorAutoProxyCreator,并重写 findCandidateAdvisors 方法。它在父类的基础上,还会对@Aspect 修饰的切面 bean 的每个增强方法,创建对应的增强容器 Advisor,类型为InstantiationModelAwarePointcutAdvisor,作为候选 advisor。这些 advisor 只会创建一次,然后放到 map 缓存在 APC

  • 增强方法是@Around、@Before、@After、@AfterReturning、@AfterThrowing 其中之一的注解修饰的方法,实现具体的增强逻辑
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public List<Advisor> buildAspectJAdvisors() {
... ...
// 获取所有beanName
String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory, Object.class, true, false);
for (String beanName : beanNames) {
... ...
if (this.advisorFactory.isAspect(beanType)) {
... ...
// 把切面中的每个增强方法(@Around、@Before、@After、@AfterReturning、@AfterThrowing之一的注解修饰)封装为一个增强容器advisor(advisor包括pointcut切点类、advice增强类)
for (Method method : getAdvisorMethods(aspectClass)) {
... ...
Advisor advisor = new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod, this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
if (advisor != null) {
advisors.add(advisor);
}
}
... ...
this.advisorsCache.put(beanName, advisors);
}
}
... ...
return advisors;
}

加载完候选 advisor bean 后,调用模板方法isEligibleBean,筛选 advisor bean。

  • AnnotationAwareAspectJAutoProxyCreator返回 true,不过滤 advisor bean。
  • InfrastructureAdvisorAutoProxyCreator筛选的是 role=ROLE_INFRASTRUCTURE 的基础设施 advisor bean
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
protected List<Advisor> findCandidateAdvisors() {
// 从beanFactory加载所有advisor类型增强器bean
... ...
advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory, Advisor.class, true, false);
... ...
for (String name : advisorNames) {
// 不同的APC实现类区分要返回哪些候选advisors,例如InfrastructureAdvisorAutoProxyCreator只会返回role=ROLE_INFRASTRUCTURE的基础设施advisor bean
if (isEligibleBean(name)) {
advisors.add(this.beanFactory.getBean(name, Advisor.class));
}
}

... ...
return advisors;
}

bean 后置初始化处理

入口:org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#postProcessAfterInitialization

跳过无需代理的 bean

读缓存,如果 bean 无需代理(说明是 aop 组件 bean),直接返回

  • bean 前置实例化处理时,已经将无需代理的 bean 加入缓存
1
2
3
4
// aop组件bean和@Aspect定义的切面类不需要被代理
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}

获取与当前 bean 匹配的增强容器 advisor

调用 getAdvicesAndAdvisorsForBean 方法获取与当前 bean 匹配的 advisor。如果存在,则 bean 需要被代理,否则不用代理。缓存 bean 是否需要代理的结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if (specificInterceptors != DO_NOT_PROXY) {
// bean需要被代理
this.advisedBeans.put(cacheKey, Boolean.TRUE);
// 创建代理
Object proxy = createProxy(
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
// 缓存代理类
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
// bean无需代理
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;

getAdvicesAndAdvisorsForBean 方法内部调用 findEligibleAdvisors 方法查找与 bean 匹配的 advisors,主要逻辑为:

  • findCandidateAdvisors 方法获取所有增强容器 advisor bean,AnnotationAwareAspectJAutoProxyCreator还会解析 Aspect 注解修饰的切面类生成的增强容器 advisor,然后调用模板方法isEligibleBean判断 advisor 是否符合条件,AnnotationAwareAspectJAutoProxyCreator 返回 true,InfrastructureAdvisorAutoProxyCreator 筛选的是 role=ROLE_INFRASTRUCTURE 的基础设施 advisor bean。该方法上面重点介绍过
  • 逐个遍历 advisor,筛选与 bean 方法匹配成功的增强容器 advisor
    • 基于增强容器 advisor 的切点Pointcut的方法匹配器MethodMatcher,逐一匹配 bean 的所有方法,匹配成功则 advisor 可用于代理 bean
  • 如果存在基于 Aspect 切面类生成的增强器 advisor:InstantiationModelAwarePointcutAdvisor,bean 的增强器链表首部添加一个 Spring 自带的增强器DefaultPointcutAdvisor
1
2
3
4
5
6
7
8
9
10
11
12
13
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
// 获取所有xml定义的增强容器advisor 和 解析Aspect注解修饰的切面类生成的增强容器advisor
List<Advisor> candidateAdvisors = findCandidateAdvisors();
// 筛选与bean方法匹配成功的增强容器advisor
// 基于增强容器advisor的切点pointCut的方法匹配器methodMatcher,逐一匹配bean的所有方法,匹配成功则advisor可用于代理bean
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
// 如果存在基于Aspect切面类生成的增强器advisor:`InstantiationModelAwarePointcutAdvisor`,bean的增强器链表首部添加一个Spring自带的增强器`DefaultPointcutAdvisor`
extendAdvisors(eligibleAdvisors);
if (!eligibleAdvisors.isEmpty()) {
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}
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 static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
... ...

MethodMatcher methodMatcher = pc.getMethodMatcher();
// 切点匹配任何方法时
if (methodMatcher == MethodMatcher.TRUE) {
return true;
}
... ...

/**
* 获取bean的所有方法(包括实现的接口里定义的所有方法)
* 基于切点PointCut的方法匹配器methodMatcher,对每个bean实现的方法做匹配,如果匹配上,说明当前增强器可以应用于这个bean
*/
... ...
classes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetClass));

for (Class<?> clazz : classes) {
Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
for (Method method : methods) {
if (introductionAwareMethodMatcher != null ?
introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) :
methodMatcher.matches(method, targetClass)) {
return true;
}
}
}
return false;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
for (Advisor advisor : advisors) {
if (isAspectJAdvice(advisor)) {
foundAspectJAdvice = true;
}
}
if (foundAspectJAdvice && !advisors.contains(ExposeInvocationInterceptor.ADVISOR)) {
advisors.add(0, ExposeInvocationInterceptor.ADVISOR);
... ...
}

private static boolean isAspectJAdvice(Advisor advisor) {
return (advisor instanceof InstantiationModelAwarePointcutAdvisor ||
advisor.getAdvice() instanceof AbstractAspectJAdvice ||
(advisor instanceof PointcutAdvisor &&
((PointcutAdvisor) advisor).getPointcut() instanceof AspectJExpressionPointcut));
}

创建 aop 代理类

创建 aop 代理,作为 bean 初始化后置处理返回值

1
2
3
4
5
// 创建代理
Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
// 缓存代理类
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;

下面看下创建 aop 代理的具体实现

创建代理工厂,从 apc bean 复制一些控制属性

1
2
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.copyFrom(this);
1
2
3
4
5
6
7
8
public void copyFrom(ProxyConfig other) {
Assert.notNull(other, "Other ProxyConfig object must not be null");
this.proxyTargetClass = other.proxyTargetClass;
this.optimize = other.optimize;
this.exposeProxy = other.exposeProxy;
this.frozen = other.frozen;
this.opaque = other.opaque;
}

如果 proxyFactory.proxyTargetClass=false,动态决定是否设为 true

  • 如果被代理 bean 的 bd 的 preserveTargetClass=true,则 proxyFactory.proxyTargetClass=true
  • 如果被代理的 bean 没有实现用户自定义接口,proxyFactory.proxyTargetClass=true。否则,将被代理 bean 实现的所有接口添加到 proxyFactory
1
2
3
4
5
6
7
8
9
10
if (!proxyFactory.isProxyTargetClass()) {
// 如果被代理bean的bd的preserveTargetClass=true,则proxyFactory.proxyTargetClass=true
if (shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true);
}
else {
// 如果被代理的bean没有实现用户自定义接口,proxyFactory.proxyTargetClass=true。否则,将被代理bean实现的所有接口添加到proxyFactory
evaluateProxyInterfaces(beanClass, proxyFactory);
}
}
1
2
3
4
5
6
7
public static boolean shouldProxyTargetClass(ConfigurableListableBeanFactory beanFactory, @Nullable String beanName) {
if (beanName != null && beanFactory.containsBeanDefinition(beanName)) {
BeanDefinition bd = beanFactory.getBeanDefinition(beanName);
return Boolean.TRUE.equals(bd.getAttribute(PRESERVE_TARGET_CLASS_ATTRIBUTE));
}
return false;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
protected void evaluateProxyInterfaces(Class<?> beanClass, ProxyFactory proxyFactory) {
Class<?>[] targetInterfaces = ClassUtils.getAllInterfacesForClass(beanClass, getProxyClassLoader());
boolean hasReasonableProxyInterface = false;
for (Class<?> ifc : targetInterfaces) {
// 如果bean实现了用户自定义的接口,hasReasonableProxyInterface = true
// isConfigurationCallbackInterface=true说明interface是Spring提供的回调接口
if (!isConfigurationCallbackInterface(ifc) && !isInternalLanguageInterface(ifc) && ifc.getMethods().length > 0) {
hasReasonableProxyInterface = true;
break;
}
}
if (hasReasonableProxyInterface) {
for (Class<?> ifc : targetInterfaces) {
proxyFactory.addInterface(ifc);
}
}
else {
proxyFactory.setProxyTargetClass(true);
}
}

上面筛选得到的匹配Advisor添加到 proxyFactory && 被代理 bean 添加到 proxyFactory

  • 如果筛选得到的是MethodInterceptor(Advice 的子接口),将MethodInterceptor包装成DefaultPointcutAdvisor
    • aop 表征增强逻辑的Advice,在真正执行时都被适配为它的子类MethodInterceptor
    • DefaultPointcutAdvisorPointcut匹配所有方法
1
2
3
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
proxyFactory.addAdvisors(advisors);
proxyFactory.setTargetSource(targetSource);
1
2
3
4
5
6
7
8
protected Advisor[] buildAdvisors(@Nullable String beanName, @Nullable Object[] specificInterceptors) {
... ...
for (int i = 0; i < allInterceptors.size(); i++) {
// 如果是MethodInterceptor,包装成DefaultPointcutAdvisor
advisors[i] = this.advisorAdapterRegistry.wrap(allInterceptors.get(i));
}
return advisors;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public Advisor wrap(Object adviceObject) throws UnknownAdviceTypeException {
if (adviceObject instanceof Advisor) {
return (Advisor) adviceObject;
}
if (!(adviceObject instanceof Advice)) {
throw new UnknownAdviceTypeException(adviceObject);
}
Advice advice = (Advice) adviceObject;
if (advice instanceof MethodInterceptor) {
// So well-known it doesn't even need an adapter.
return new DefaultPointcutAdvisor(advice);
}
for (AdvisorAdapter adapter : this.adapters) {
// Check that it is supported.
if (adapter.supportsAdvice(advice)) {
return new DefaultPointcutAdvisor(advice);
}
}
throw new UnknownAdviceTypeException(advice);
}

创建实际的 aop 代理类:JDK 动态代理或 CgLIB 动态代理

  • ProxyFactory继承AdvisedSupport,封装了代理上下文(被代理类、增强容器、代理配置属性等),用于控制创建 aop 代理的逻辑
  • 无特殊配置下,如果 bean 实现了用户自定义接口,创建 JDK 动态代理,否则创建 CgLIB 动态代理
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
// 如果被代理bean没实现用户自定义接口 || 被代理bean的bd.preserveTargetClass=true || apc的bd.proxyTargetClass=true
if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
Class<?> targetClass = config.getTargetClass();
if (targetClass == null) {
throw new AopConfigException("TargetSource cannot determine target class: " +
"Either an interface or a target is required for proxy creation.");
}
... ...
return new ObjenesisCglibAopProxy(config);
}
else {
// 如果实现了用户自定义接口,创建JDK动态代理
return new JdkDynamicAopProxy(config);
}
}

代理类执行方法代理

这里介绍的是 JDK 动态代理
入口:org.springframework.aop.framework.JdkDynamicAopProxy#invoke

获取方法的拦截器 MethodInterceptor 列表

获取被代理方法的方法拦截器MethodInterceptor列表

  • 从 bean 匹配的所有增强容器中,通过切点的MethodMatcher筛选出与当前方法匹配的增强容器Advisor
  • 通过适配器模式,使用一个适配器类把增强Advice包装为方法拦截器MethodInterceptor
    • aop 的表征增强逻辑的Advice,在真正执行时都被适配为它的子类MethodInterceptor
  • 缓存被代理方法与拦截器MethodInterceptor列表的映射
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
for (Advisor advisor : config.getAdvisors()) {
if (advisor instanceof PointcutAdvisor) {
// Add it conditionally.
PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
// 在原始bean匹配的所有增强器advisor里筛选与当前调用方法匹配的advisor
// 然后取出advice,适配成MethodInterceptor
if (MethodMatchers.matches(mm, method, actualClass, hasIntroductions)) {
MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
if (mm.isRuntime()) {
// Creating a new object instance in the getInterceptors() method
// isn't a problem as we normally cache created chains.
for (MethodInterceptor interceptor : interceptors) {
interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
}
}
else {
interceptorList.addAll(Arrays.asList(interceptors));
}
}
}
}
...
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {
List<MethodInterceptor> interceptors = new ArrayList<>(3);
Advice advice = advisor.getAdvice();
if (advice instanceof MethodInterceptor) {
interceptors.add((MethodInterceptor) advice);
}
// 部分类型的增强advice本身不是拦截器methodInterceptor类型
// 通过适配器将advice包装为拦截器
for (AdvisorAdapter adapter : this.adapters) {
if (adapter.supportsAdvice(advice)) {
interceptors.add(adapter.getInterceptor(advisor));
}
}
if (interceptors.isEmpty()) {
throw new UnknownAdviceTypeException(advisor.getAdvice());
}
return interceptors.toArray(new MethodInterceptor[0]);
}
1
2
3
4
5
6
7
8
9
10
11
12
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class<?> targetClass) {
MethodCacheKey cacheKey = new MethodCacheKey(method);
List<Object> cached = this.methodCache.get(cacheKey);
if (cached == null) {
// 获取被代理方法的拦截器列表
cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
this, method, targetClass);
// 缓存代理方法与拦截器列表的映射
this.methodCache.put(cacheKey, cached);
}
return cached;
}

创建代理方法上下文

创建一个代理方法上下文MethodInvocation

  • 封装执行被代理方法的上下文,包括原始 bean、被代理方法、入参,以及上一步获取的方法拦截器列表(用于执行代理逻辑)
1
2
// 创建一个代理方法调用上下文
MethodInvocation invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);

执行方法代理

调用代理方法上下文 MethodInvocation 的 proceed 方法执行方法代理,实际调用:org.springframework.aop.framework.ReflectiveMethodInvocation#proceed。回调拦截器增强方法的过程是通过递归实现的,下面具体分析。

顺序回调方法拦截器列表里每个MethodInterceptor的 invoke 方法,传入代理方法上下文。

1
2
3
4
5
...
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
...
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);

注意,MethodInvocation的 proceed 方法是一个递归调用,MethodInterceptor的实现类会在合适的时机执行增强逻辑以及继续递归调用 MethodInvocation 的 proceed 方法,以此保证了所有方法拦截器的增强逻辑都会被执行到

  • 所谓“拦截方法在合适时机执行增强逻辑”,例如前置@Before 增强对应的拦截器MethodBeforeAdviceInterceptor就会在回调代理方法前执行增强逻辑。@After 增强对应的拦截器AspectJAfterAdvice就会先回调代理方法,返回后再执行增强逻辑

MethodBeforeAdviceInterceptor:

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();
}

AspectJAfterAdvice:

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);
}
}

如果所有方法拦截器的 invoke 方法都被调用了,则反射调用被代理方法。

1
2
3
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}

注意,因为MethodInvocation的 proceed 方法是递归调用的,所以会逆序从每个方法拦截器向上 return,回溯过程中可能有些拦截器的增强逻辑才被调用,例如上面介绍的AspectJAfterAdvice

前面提到,APC 在初始化后置处理为 bean 创建动态代理的过程中,会寻找与当前 bean 匹配的增强容器 advisor,如果存在来自 Aspect 切面类生成的增强容器,会为 bean 的增强容器链表首部添加一个通配的增强容器DefaultPointcutAdvisor。该 advisor 的增强 advice 是ExposeInvocationInterceptor(interceptor 是 advice 的子接口),它的执行逻辑是将当前代理方法调用上下文 MethodInvocation 写 ThreadLocal,方便在该方法拦截器链上的其他拦截器通过其获取调用上下文,所以要放在拦截器链首部第一个执行

  • @Aspect 切面类,其增强方法的入参是拿不到 MethodInvocation 的。入参是ProceedingJoinPointJoinPoint,所以如果要拿到 MethodInvocation 需要调用org.springframework.aop.interceptor.ExposeInvocationInterceptor#currentInvocation
1
2
3
4
5
6
7
8
9
10
11
@Override
// 将当前代理方法调用上下文写ThreadLocal,方便在该方法拦截器链上的其他拦截器获取当前代理方法调用上下文
public Object invoke(MethodInvocation mi) throws Throwable {
MethodInvocation oldInvocation = invocation.get();
invocation.set(mi);
try {
return mi.proceed();
} finally {
invocation.set(oldInvocation);
}
}
1
2
3
4
5
6
7
8
public static MethodInvocation currentInvocation() throws IllegalStateException {
MethodInvocation mi = (MethodInvocation) invocation.get();
if (mi == null) {
throw new IllegalStateException("No MethodInvocation found: Check that an AOP invocation is in progress, and that the ExposeInvocationInterceptor is upfront in the interceptor chain. Specifically, note that advices with order HIGHEST_PRECEDENCE will execute before ExposeInvocationInterceptor!");
} else {
return mi;
}
}

创建 aop 的几种姿势

上面说了 aop 是如何注册自己最重要的组件 bean:apc,以及 apc 是如何为 bean 创建 aop 代理类的。接下来介绍我们在自己的应用中如何创建 aop。一般有两种方式

@Aspect 方式

如果使用这种 AspectJ 注解方式,通过上面的分析,我们知道需要依赖 APC:AnnotationAwareAspectJAutoProxyCreator,来解析@Aspect 修饰的切面类,动态注册 advisor。因此需要引入这个 apc,xml 通过<aop:aspectj-autoproxy/>,注解方式使用@EnableAspectJAutoProxy

注册自定义的 advisor bean

我们也可以自己注册自定义的 advisor bean,当然这也需要 bf 里有 apc 来把这些 advisor bean 搂出来。
如果我们依然使用<aop:aspectj-autoproxy/>@EnableAspectJAutoProxy来注册 APC:AnnotationAwareAspectJAutoProxyCreator,那么我们的 advisor bean 会被搂出来,因为他不会做任何过滤。
如果我们不想使用 AnnotationAwareAspectJAutoProxyCreator,而是 InfrastructureAdvisorAutoProxyCreator,那么可以通过 Import 的方式导入 bd 注册器:AutoProxyRegistrar,且配置类的注解里必须包含参数 mode(值为 AdviceMode.PROXY) 和 proxyTargetClass(Boolean 类型),则 AutoProxyRegistrar 会向 bf 注册 InfrastructureAdvisorAutoProxyCreator。
此时我们在配置 advisor bean 时,需要增加注解:@Role(BeanDefinition.ROLE_INFRASTRUCTURE),来标识我们的 advisor bean 是基础设施 bean,否则不会被搂出来。

advisor 的基类我们一般选择PointcutAdvisor,它包含两部分:advice 和 pointCut

1
2
3
4
5
public interface Advisor {
Advice getAdvice();

boolean isPerInstance();
}
1
2
3
public interface PointcutAdvisor extends Advisor {
Pointcut getPointcut();
}

我们自定义的 advisor 一般继承AbstractPointcutAdvisor,它实现了 Ordered,我们可以给自定义的 advisor 指定 order 来决定 advisor 在代理方法里执行的先后顺序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public abstract class AbstractPointcutAdvisor implements PointcutAdvisor, Ordered, Serializable {
private Integer order;

public AbstractPointcutAdvisor() {
}

public void setOrder(int order) {
this.order = order;
}

public int getOrder() {
if (this.order != null) {
return this.order;
} else {
Advice advice = this.getAdvice();
return advice instanceof Ordered ? ((Ordered)advice).getOrder() : 2147483647;
}
}
... ...
}

Pointcut

先看 PointCut 的定义,可以发现切的规则分为两部分:按类型切和按方法切

1
2
3
4
5
6
7
public interface Pointcut {
Pointcut TRUE = TruePointcut.INSTANCE;

ClassFilter getClassFilter();

MethodMatcher getMethodMatcher();
}

Spring 提供了一些好用的 PointCut 抽象类我们可以直接继承来用

StaticMethodMatcherPointcut

如果我们只关心按方法切,类型不 care。可以继承StaticMethodMatcherPointcut,它默认的 ClassFilter 为 true(不过你也可以指定 ClassFilter),即不过滤 class。我们继承并重写 matches 方法来过滤出要切的方法即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public abstract class StaticMethodMatcherPointcut extends StaticMethodMatcher implements Pointcut {
private ClassFilter classFilter;

public StaticMethodMatcherPointcut() {
this.classFilter = ClassFilter.TRUE;
}

public void setClassFilter(ClassFilter classFilter) {
this.classFilter = classFilter;
}

public ClassFilter getClassFilter() {
return this.classFilter;
}

public final MethodMatcher getMethodMatcher() {
return this;
}
}

NameMatchMethodPointcut

NameMatchMethodPointcut 是 StaticMethodMatcherPointcut 的子类,它维护一组注册给它的方法名 List,只要方法名在维护的 List 里,就切方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class NameMatchMethodPointcut extends StaticMethodMatcherPointcut implements Serializable {
... ...

public boolean matches(Method method, Class<?> targetClass) {
Iterator var3 = this.mappedNames.iterator();

String mappedName;
do {
if (!var3.hasNext()) {
return false;
}

mappedName = (String)var3.next();
} while(!mappedName.equals(method.getName()) && !this.isMatch(method.getName(), mappedName));

return true;
}

protected boolean isMatch(String methodName, String mappedName) {
return PatternMatchUtils.simpleMatch(mappedName, methodName);
}
}

AnnotationMatchingPointcut

如果我们想要切被特定注解修饰的 class 或 method,可以使用AnnotationMatchingPointcut,通过构造函数指定类上、方法上需要的注解 class 即可

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
public class AnnotationMatchingPointcut implements Pointcut {
private final ClassFilter classFilter;
private final MethodMatcher methodMatcher;

public AnnotationMatchingPointcut(Class<? extends Annotation> classAnnotationType) {
this.classFilter = new AnnotationClassFilter(classAnnotationType);
this.methodMatcher = MethodMatcher.TRUE;
}

public AnnotationMatchingPointcut(Class<? extends Annotation> classAnnotationType, Class<? extends Annotation> methodAnnotationType) {
Assert.isTrue(classAnnotationType != null || methodAnnotationType != null, "Either Class annotation type or Method annotation type needs to be specified (or both)");
if (classAnnotationType != null) {
this.classFilter = new AnnotationClassFilter(classAnnotationType);
} else {
this.classFilter = ClassFilter.TRUE;
}

if (methodAnnotationType != null) {
this.methodMatcher = new AnnotationMethodMatcher(methodAnnotationType);
} else {
this.methodMatcher = MethodMatcher.TRUE;
}

}
... ...
}

Advice

Advice 表示代理的增强逻辑,但它是个空接口,我们的 advice 一般都实现MethodInterceptor这个子接口

1
2
3
public interface MethodInterceptor extends Interceptor {
Object invoke(MethodInvocation var1) throws Throwable;
}

SpringBoot 方式

SpringBoot 引入 jar 包:spring-boot-autoconfigure,该 jar 包下定义了很多 SpringBoot 应用需要的配置类,在 Spring 容器初始化过程中,会自动注册配置类:AopAutoConfiguration。这就是 SpringBoot 的 starter 机制,另一篇里有详细介绍。
AopAutoConfiguration 会引入注解 EnableAspectJAutoProxy,所以 SpringBoot 应用自带 APC:AnnotationAwareAspectJAutoProxyCreator,因此无论是@Aspect 声明的切面类或者我们自定义的 advisor 都会生效

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
@Configuration
@ConditionalOnClass({EnableAspectJAutoProxy.class, Aspect.class, Advice.class, AnnotatedElement.class})
@ConditionalOnProperty(
prefix = "spring.aop",
name = {"auto"},
havingValue = "true",
matchIfMissing = true
)
public class AopAutoConfiguration {
public AopAutoConfiguration() {
}

@Configuration
@EnableAspectJAutoProxy(
proxyTargetClass = true
)
@ConditionalOnProperty(
prefix = "spring.aop",
name = {"proxy-target-class"},
havingValue = "true",
matchIfMissing = true
)
public static class CglibAutoProxyConfiguration {
public CglibAutoProxyConfiguration() {
}
}

@Configuration
@EnableAspectJAutoProxy(
proxyTargetClass = false
)
@ConditionalOnProperty(
prefix = "spring.aop",
name = {"proxy-target-class"},
havingValue = "false",
matchIfMissing = false
)
public static class JdkDynamicAutoProxyConfiguration {
public JdkDynamicAutoProxyConfiguration() {
}
}
}