学成路更宽,吊打面试官。 ——小马哥
版本修订
- 2021.5.19:去除目录
简介
大家好,我是小马哥成千上万粉丝中的一员!2019年8月有幸在叩丁狼教育举办的猿圈活动中知道有这么一位大咖,从此结下了不解之缘!此系列在多次学习极客时间《小马哥讲Spring AOP 编程思想》基础上形成的个人一些总结。希望能帮助各位小伙伴, 祝小伙伴早日学有所成。
AdvisorChainFactory 功能
AdvisorChainFactory
接口只有唯一一个方法就是 List<Object> getInterceptorsAndDynamicInterceptionAdvice(Advised config, Method method, @Nullable Class<?> targetClass)
。根据 javadoc 介绍此方法是根据方法参数 config
返回 MethodInterceptor
列表,在 Spring AOP 内部只有一个唯一实现 DefaultAdvisorChainFactory
。
前置知识
Advised
Advised 功能
从 javadoc 可知: 此接口实现类拥有配置 AOP 代理工厂的能力(AopProxyFactory #createAopProxy
方法参数就是此实现类 ),此配置包含 Interceptor
和 Advice
、Advisor
和 代理接口
。从 Spring
获得的任何 AOP 代理
都可以转换到这个接口,以允许操作它的 AOP Advice
(详情请跟踪 CglibAopProxy
中调用 AopProxyUtils#completeProxiedInterfaces(AdvisedSupport advised)
和 JdkDynamicAopProxy
中调用 AopProxyUtils.completeProxiedInterfaces((AdvisedSupport advised, boolean decoratingProxy)
会发现宝藏)。
Advised 方法简介
- boolean isFrozen():Advised 配置是否冻结,冻结之后不能更改任何 Advice。
- boolean isProxyTargetClass():对应
@EnableAspectJAutoProxy
中的proxyTargetClass
属性 - Class<?>[] getProxiedInterfaces():返回由AOP代理代理的接口
- boolean isInterfaceProxied(Class<?> intf):判断给定接口是否被代理
- void setTargetSource(TargetSource targetSource):更改当前 Advised 对象使用的TargetSource,仅当配置不是 isFrozen 为 true 时有效。
- TargetSource getTargetSource():获取当前 Advised 对象使用的 TargetSource
- void setExposeProxy(boolean exposeProxy):对应
@EnableAspectJAutoProxy
中的exposeProxy
属性 - boolean isExposeProxy():返回工厂是否应该将代理暴露到 ThreadLocal(AopContext)。如果 Advise 的对象需要在应用 Advice 的情况下调用自身的方法,则有必要公开代理。否则,如果 Advice 的对象对此调用一个方法,则不会应用任何 Advice。获取代理类似于调用getEJBObject()的EJB。
- void setPreFiltered(boolean preFiltered):设置此代理配置是否经过预过滤,以便仅包含可用的 Advisor (匹配此代理的目标类)。默认设置是
false
。如果 Advisor 已经被预先过滤,则将其设置为true
,这意味着在为代理调用构建实际的 Advisor 链时可以跳过ClassFilter
检查。 - boolean isPreFiltered():返回此代理配置是否已预过滤,以便仅过滤包含可用的 Advisor (匹配此代理的目标类)。
- Advisor[] getAdvisors():返回应用于当前代理的 Advisor 列表
- void addAdvisor(Advisor advisor):在 Advisor 链末尾添加 Advisor
- void addAdvisor(int pos, Advisor advisor):在 Advisor 链指定的位置添加 Advisor
- boolean removeAdvisor(Advisor advisor):移除指定 Advisor
- void removeAdvisor(int index):移除指定位置的 Advisor
- int indexOf(Advisor advisor):检索 Advisor 在 Advisor 链中的位置
- boolean replaceAdvisor(Advisor a, Advisor b):替换指定 Advisor
- void addAdvice(Advice advice):添加 Advice 到 Advice 链末端(根据 Advice类型不同会被包装成
DefaultPointcutAdvisor
或者DefaultIntroductionAdvisor
) - void addAdvice(int pos, Advice advice):在 Advice 链指定的位置添加 Advisor
- boolean removeAdvice(Advice advice):移除指定 Advice
- int indexOf(Advice advice):检索 Advice 在 Advice 链中的位置
- String toProxyConfigString():代理配置的字符串描述
Advisor
Advisor 功能
从 javadoc 可知: 此接口是保存 AOP Advice(在连接点上要采取的动作)的基本接口和决定可用的 Adivce(如切入点)的过滤器。这个接口不是供 Spring 用户使用的,而是为了支持不同类型的 Advice。
Spring AOP 是基于通过方法拦截来传递 Around Advice(所以没有单独有 Around 类型的 Advice),符合 AOP Alliance 拦截 API。Advisor 接口允许支持不同类型的 Advice,比如 before 和 after Advice。
Advisor 方法简介
- Advice getAdvice():返回切面的 Advice 部分。 Advice 可以是
MethodInterceptor
、BeforeAdvice
,ThrowsAdvice
等 - boolean isPerInstance():返回该
Advice
是否与特定的实例相关联(例如,创建混合),或者与从同一 Spring bean 工厂获得的被通知类的所有实例共享。注意,该框架目前没有使用此方法。典型的Advisor
实现总是返回true
。使用单例/原型 bean 定义或适当的编程代理创建来确保 Advisor 拥有正确的生命周期模型。
AdvisorAdapter
AdvisorAdapter功能
从 javadoc 中可知: 此接口是对 Spring AOP 框架进行扩展,以允许处理新的(自定义的) Advisors 和 Advice 类型。
实现对象可以从自定义 Advice 类型创建 AOP Alliance Interceptor,使这些 Advice 类型可以在 Spring AOP 框架中使用,后者在底层使用拦截。
大多数 Spring 用户不需要实现这个接口;只有在需要向 Spring 引入更多 Advisor 或 Advice 类型时才这样做。
总结一句话: 就是对 Advisors 和 Advice 类型扩展,底层是通过拦截器实现,由于 Spring 只支持方法级别的拦截所以拦截器都实现了 MethodInterceptor
AdvisorAdapter 方法简介
- boolean supportsAdvice(Advice advice):是否支持此 Advice 对象
- MethodInterceptor getInterceptor(Advisor advisor):返回一个AOP Alliance MethodInterceptor,将给定 Advice 的行为暴露给一个基于拦截的 AOP 框架。不要担心 Advisor 中包含的任何 Pointcut ;AOP 框架将负责检查 Pointcut。
AdvisorAdapterRegistry
AdvisorAdapterRegistry 功能
从 javadoc 中可知: 此接口是注册 AdvisorAdapter(这是一个 SPI 接口,不是由任何 Spring 用户实现的),在 Spring AOP 内部只有一个唯一实现 DefaultAdvisorAdapterRegistry
。
AdvisorAdapterRegistry 方法简介
- Advisor wrap(Object advice):把给定的 Adivice 对象包装成 Advisor
- MethodInterceptor[] getInterceptors(Advisor advisor):把 Advisor 转换成 MethodInterceptor
- void registerAdvisorAdapter(AdvisorAdapter adapter):注册 AdvisorAdapter (用于扩展 AdvisorAdapter )
Pointcut
Pointcut 功能
从 javadoc 中可知: 此接口是 Spring Pointcut 核心抽象。Pointcut 由一个 ClassFilter
和一个MethodMatcher
组成
总结一句话: Pointcut 要先经过类型匹配上了之后再通过方法进行匹配
Pointcut 方法简介
- ClassFilter getClassFilter():获取 Pointcut 关联的 ClassFilter 实现
- MethodMatcher getMethodMatcher():获取 Pointcut 关联的 MethodMatcher 实现
MethodMatcher
MethodMatcher 功能
从 javadoc 中可知: 此接口是 Pointcut 的一部分:用于检查目标方法是否有资格获得 Advice。
MathodMatcher 可以静态地或在运行时(动态地)计算。静态匹配涉及方法和(可能)方法属性。动态匹配还使特定调用的参数可用,以及将先前的 Advice 应用到 Joinpoint的任何效果。
如果实现 isRuntime()
方法返回 false
,则可以静态执行求值,并且该方法的所有调用的结果都是相同的,无论它们的参数是什么。这意味着如果 isRuntime()
方法返回 false
,则 3 参数 matches(Method method, Class<?> targetClass, Object... args)
方法将永远不会被调用。
如果一个实现从它的 2 参数 matches(Method method, Class<?> targetClass)
返回 true
和它的 isRuntime()
方法返回 true
, 3 参数 matches(Method method, Class<?> targetClass, Object... args)
方法将在相关 Advice 的每次潜在执行之前被立即调用,以决定该 Advice 是否应该运行。之前的所有 Adivce (比如拦截器链中的早期拦截器)都将运行,因此它们在参数或 ThreadLocal 状态中产生的任何状态更改都将在计算时可用。
该接口的具体实现通常应该提供 Object.equals(Object) 和 Object. hashcode() 的适当实现,以便允许匹配器在缓存场景中使用——例如,在 CGLIB 生成的代理中。
总结一句话: 如果 2个参数的 boolean matches(Method method, Class<?> targetClass)
方法返回 true
,isRuntime()
方法也是 true
则会调用 3 个参数 matches(Method method, Class<?> targetClass, Object... args)
方法如果返回 true
再进行 Advice
MethodMatcher 方法简介
- boolean matches(Method method, Class<?> targetClass):执行静态检查给定的方法是否匹配,如果返回
false
或isRuntime()
方法返回false
,则不进行运行时检查(即不matches(java.lang.reflect.Method, Class, Object[])
调用) - boolean isRuntime():这个
MethodMatcher
是动态还是静态 - boolean matches(Method method, Class<?> targetClass, Object… args):只有上述2个方法都返回
true
才执行。
前置知识大总结
- 通过
Pointcut
关联的ClassFilter
和MethodMatcher
筛选构成Joinpoint
,然后再基于不同Advice
类型进行执行动作。 - Spring AOP 框架内部有个全局对象
GlobalAdvisorAdapterRegistry
,它内部关联一个AdvisorAdapterRegistry
对象。通过AdvisorAdapterRegistry#registerAdvisorAdapter
方法注册AdvisorAdapter
。可以通过Adviced
对象可获得Advisor
对象或者由AdvisorAdapterRegistry#wrap()
方法获得Advisor
对象。通过AdvisorAdapterRegistry#getInterceptors
方法获取MethodInterceptor
数组。
AdvisorChainFactory 源码解析
由于 AdvisorChainFactory
只有一个唯一实现 DefaultAdvisorChainFactory
源码分析则是在此类进行。
@Override
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
Advised config, Method method, @Nullable Class<?> targetClass) {
// 获取 AdvisorAdapterRegistry
AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
// 获取 Advisor 列表
Advisor[] advisors = config.getAdvisors();
List<Object> interceptorList = new ArrayList<>(advisors.length);
Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
Boolean hasIntroductions = null;
for (Advisor advisor : advisors) {
// Advisor 对象是否是 PointcutAdvisor 实例,PointcutAdvisor 具有 Pointcut(过滤) 和 Advisor(动作) 功能
if (advisor instanceof PointcutAdvisor) {
// 获取 PointcutAdvisor .
PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
// Advised 配置对象是否设置了预过滤,如果设置了跳过 ClassFilter 检查,如果没有通过则 通过 Pointcut 中关联的 ClassFilter#matches 方法进行检查。
if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
// 类型匹配之后,再进行方法匹配
MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
boolean match;
if (mm instanceof IntroductionAwareMethodMatcher) {
if (hasIntroductions == null) {
hasIntroductions = hasMatchingIntroductions(advisors, actualClass);
}
match = ((IntroductionAwareMethodMatcher) mm).matches(method, actualClass, hasIntroductions);
}
else {
match = mm.matches(method, actualClass);
}
// 方法匹配则通过 AdvisorAdapterRegistry 获取 MethodInterceptor 数组 if (match) {
MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
// 如果 MethodMatcher 实现对象是动态匹配,则会调用 MethodMatcher#matches(Method method, Class<?> targetClass, Object... args)
if (mm.isRuntime()) {
for (MethodInterceptor interceptor : interceptors) {
interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
}
}
else {
interceptorList.addAll(Arrays.asList(interceptors));
}
}
}
}
// 如果 Advisor 对象是 IntroductionAdvisor 实例,通过类型匹配之后,接口所有的方法都要代理
else if (advisor instanceof IntroductionAdvisor) {
IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
// 通过 AdvisorAdapterRegistry 获取 MethodInterceptor 数组
Interceptor[] interceptors = registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
}
}
else {
/**
* 如果不是 PointcutAdvisor 和 IntroductionAdvisor 即是普通的 Advisor。
* 通过 AdvisorAdapterRegistry 获取 MethodInterceptor 数组
*/
Interceptor[] interceptors = registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
}
}
return interceptorList;
}