前提:
https://blog.csdn.net/convict_eva/article/details/81084833
https://blog.csdn.net/convict_eva/article/details/81101432
前两篇分析了aop 两种方式实现的大致流程和方式,在这两种实现方式中都有一个很重要的方法获取拦截器链
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
所有的aop增强方法都封装在一个个拦截器中,然后根据这个拦截器链的调用进行增强。
此方法的实现是在advised 对象实现的(advised 是 AdvisedSupport 对象的实例,ProxyFactoryBean 是AdvisedSupport 子类)
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class<?> targetClass) {
MethodCacheKey cacheKey = new MethodCacheKey(method);
//这里使用了缓存来提高效率,第一次获取还是要创建的。
//使用了 advisorChainFactory 生成拦截器链,advisorChainFactory 是 DefaultAdvisorChainFactory 的实例
List<Object> cached = this.methodCache.get(cacheKey);
if (cached == null) {
cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
this, method, targetClass);
this.methodCache.put(cacheKey, cached);
}
return cached;
}
advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice()源码:
@Override
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
Advised config, Method method, @Nullable Class<?> targetClass) {
// This is somewhat tricky... We have to process introductions first,
// but we need to preserve order in the ultimate list.
//初始化拦截器链,大小是通知器个数。这个配置就是 ProxyFactoryBean 的 interceptNames 的属性配置。
List<Object> interceptorList = new ArrayList<>(config.getAdvisors().length);
Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
boolean hasIntroductions = hasMatchingIntroductions(config, actualClass);
//获取 AdvisorAdapterRegistry 实例,AdvisorAdapterRegistry被称为“注册器”
//利用它来对从ProxyFactoryBean 配置中得到的通知器进行适配,从而获得相应的拦截器,再把拦截器加入到拦截器链中
AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
for (Advisor advisor : config.getAdvisors()) {
if (advisor instanceof PointcutAdvisor) {
// Add it conditionally.
PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
//通过 AdvisorAdapterRegistry 获取拦截器,这个方法封装了advice 织入的实现入口
MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
//获取 MethodMatcher ,用来匹配目标方法,如果匹配就放入到拦截器链中。pointcut 就是在这里使用的
MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
if (MethodMatchers.matches(mm, method, actualClass, hasIntroductions)) {
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));
}
}
}
}
else if (advisor instanceof IntroductionAdvisor) {
IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
Interceptor[] interceptors = registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
}
}
else {
Interceptor[] interceptors = registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
}
}
return interceptorList;
}
通过GlobalAdvisorAdapterRegistry 获取一个单例的 AdvisorAdapterRegistry 实例
AdvisorAdapterRegistry 的实现是 DefaultAdvisorAdapterRegistry
DefaultAdvisorAdapterRegistry.getInterceptors() 方法封装了advice 织入实现的入口
注:在ProxyFactoryBean 中已经把配置的advice封装成了 Advisor,第一篇有介绍。
DefaultAdvisorAdapterRegistry 类源码分析:
public class DefaultAdvisorAdapterRegistry implements AdvisorAdapterRegistry, Serializable {
//advisor 适配器列表
private final List<AdvisorAdapter> adapters = new ArrayList<>(3);
/**
* Create a new DefaultAdvisorAdapterRegistry, registering well-known adapters.
定义了3个适配器, 就是这3个适配器为aop提供编织能力。
这3个适配器和spring aop提供的advice增强功能相对就的
这3个是spring aop advice的封装实现
*/
public DefaultAdvisorAdapterRegistry() {
registerAdvisorAdapter(new MethodBeforeAdviceAdapter());
registerAdvisorAdapter(new AfterReturningAdviceAdapter());
registerAdvisorAdapter(new ThrowsAdviceAdapter());
}
//省略方法......
@Override
public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {
List<MethodInterceptor> interceptors = new ArrayList<>(3);
//从advisor通知器中获取advice通知
Advice advice = advisor.getAdvice();
if (advice instanceof MethodInterceptor) {
//如果是MethodInterceptor 直接加入到MethodInterceptor list 中不需要适配
interceptors.add((MethodInterceptor) advice);
}
//对通知器进行适配,使用构造时已经配置好的adapter(上面3种adapter)
//然后从对应的adapter 中取出封装好的aop编织功能的拦截器
//通过adapter.getInterceptor() 方法返回对应的是3种 MethodInterceptor。
//这里就是第一篇分析的invoke获取拦截器链调用的 MethodInterceptor
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]);
}
//可以自己定义adapter
@Override
public void registerAdvisorAdapter(AdvisorAdapter adapter) {
this.adapters.add(adapter);
}
}
adapter 有三种实现方式
这里使用MethodBeforeAdviceAdapter说明:就是判断一下advice类型,然后把advice 封装成MethodInterceptor
class MethodBeforeAdviceAdapter implements AdvisorAdapter, Serializable {
//这里验证是否是 MethodBeforeAdvice 类型
@Override
public boolean supportsAdvice(Advice advice) {
return (advice instanceof MethodBeforeAdvice);
}
@Override
public MethodInterceptor getInterceptor(Advisor advisor) {
//获取advice,创建 MethodBeforeAdviceInterceptor 对象并返回
MethodBeforeAdvice advice = (MethodBeforeAdvice) advisor.getAdvice();
return new MethodBeforeAdviceInterceptor(advice);
}
}
这里获取了advisor 对应的 MethodInterceptor之后,就要对这MethodInterceptor 进行匹配了
匹配使用的是通过 advisor.getPointcut().getMethodMatcher() 获取到 MethodMatcher 对象进行匹配验证的。
总结:
通过配置 ProxyFactoryBean interceptorNames 属性来配置advice,ProxyFactoryBean 调用 initializeAdvisorChain() 方法把这些配置解析成 advisor链(advisor 包含了advice 和 pointcut)。
在代理对象调用目标方法时,通过 DefaultAdvisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice() 方法获取到拦截器链,这个方法又是调用 DefaultAdvisorAdapterRegistry.getInterceptors() 方法生成的拦截器链。
spring aop 就是通过拦截器模式调用这些生成的拦截器实现的aop功能
————————————————
版权声明:本文为CSDN博主「Jamin_Ma」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/convict_eva/article/details/81105144