7.Spring 源码解析之AOP获取增强器过程
7.1 Spring 注解之 @EnableAspectJAutoProxy
Spring 开启自动代理是通过 @EnableAspectJAutoProxy
来实现的,看看这个注解都有哪些功能,代码如下:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
boolean proxyTargetClass() default false;
boolean exposeProxy() default false;
}
发现引入了AspectJAutoProxyRegistrar.class
组件,内部主要实现了注册 AnnotationAwareAspectJAutoProxyCreator.class
组件,代码如下:
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry)
|- registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
|- registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
|- public static final String AUTO_PROXY_CREATOR_BEAN_NAME =
"org.springframework.aop.config.internalAutoProxyCreator";
AnnotationAwareAspectJAutoProxyCreator.class
这个类的组织关系,如下图所示:
发现这个类是一个BeanPostProcessor,该类在bean生命周期中,分析过 ,这里不再赘述。在生命周期中的函数主要有以下几个。
7.2 Spring 获取增强器过程
在bean实例化过程中,先调用 postProcessBeforeInstantiation()
,经过源码分析,该函数主要做了切面解析过程,主要逻辑如下:
// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
从注释中我们可以看到,该方法主要作用是:给一个机会返回一个目标bean实例的代理对象。
if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
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;
}
protected boolean isInfrastructureClass(Class<?> beanClass) {
return (super.isInfrastructureClass(beanClass) ||
(this.aspectJAdvisorFactory != null &&
this.aspectJAdvisorFactory.isAspect(beanClass)));
}
判断当前类是否是切面类,如果是,直接返回,因为切面类肯定不需要增强,不是时,会调用shouldSkip
,调用过程如下:
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.
if (this.aspectJAdvisorsBuilder != null) {
advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
}
return advisors;
}
这里面主要查找两种增强,Spring advisor(事务等用的) 和 AspectJ aspects(@Aspect用的)
7.2.1 获取 Spring Advisor
Spring 原生的 Advisor 是通过检索工具类来实现的,BeanFactoryAdvisorRetrievalHelper
advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.beanFactory, Advisor.class, true, false);
查找所有Advisor家族的类,AnnotationAwareAspectJAutoProxyCreator
没有实现过Advisor,这部分等到后面事务在解析。
7.2.2 获取 AspectJ Advisor
buildAspectJAdvisors
利用了缓存,在AnnotationAwareAspectJAutoProxyCreator
中存放了 aspectBeanNames
所有的切面beanName。具体是通过查找所有的组件,然后一个个匹配的思想,解析一遍比较耗时,要给缓存起来。
String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.beanFactory, Object.class, true, false);
然后循环这些beanName,把这些beanName 转换成beanType,然后判断这些beanType是不是切面类。
private boolean hasAspectAnnotation(Class<?> clazz) {
return (AnnotationUtils.findAnnotation(clazz, Aspect.class) != null);
}
然后获取切面类所有方法,排除掉@Pointcut方法,这个是获取切点表达式使用的。
private List<Method> getAdvisorMethods(Class<?> aspectClass) {
List<Method> methods = new ArrayList<>();
ReflectionUtils.doWithMethods(aspectClass, methods::add, adviceMethodFilter);
if (methods.size() > 1) {
methods.sort(adviceMethodComparator);
}
return methods;
}
// Exclude @Pointcut methods
private static final MethodFilter adviceMethodFilter =
ReflectionUtils.USER_DECLARED_METHODS.and(
method -> (AnnotationUtils.getAnnotation(method, Pointcut.class) == null));
-
获取切点表达式
AspectJExpressionPointcut expressionPointcut = getPointcut( candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
-
组装Advisor类
new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod, this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
-
获取方法上的注解
AspectJAnnotation<?> aspectJAnnotation = AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
-
创建通知
switch (aspectJAnnotation.getAnnotationType()) { case AtPointcut: if (logger.isDebugEnabled()) { logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'"); } return null; case AtAround: springAdvice = new AspectJAroundAdvice( candidateAdviceMethod, expressionPointcut, aspectInstanceFactory); break; case AtBefore: springAdvice = new AspectJMethodBeforeAdvice( candidateAdviceMethod, expressionPointcut, aspectInstanceFactory); break; case AtAfter: springAdvice = new AspectJAfterAdvice( candidateAdviceMethod, expressionPointcut, aspectInstanceFactory); break; case AtAfterReturning: springAdvice = new AspectJAfterReturningAdvice( candidateAdviceMethod, expressionPointcut, aspectInstanceFactory); AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation(); if (StringUtils.hasText(afterReturningAnnotation.returning())) {![aop-2](D:\code\idea\atom\spring\image\新建文件夹\aop-2.png) springAdvice.setReturningName(afterReturningAnnotation.returning()); } break; case AtAfterThrowing: springAdvice = new AspectJAfterThrowingAdvice( candidateAdviceMethod, expressionPointcut, aspectInstanceFactory); AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation(); if (StringUtils.hasText(afterThrowingAnnotation.throwing())) { springAdvice.setThrowingName(afterThrowingAnnotation.throwing()); } break; default: throw new UnsupportedOperationException( "Unsupported advice type on method: " + candidateAdviceMethod); }
每个方法都遍历完后,获取到的Advisors 和beanName 促成一个map,存放到缓存中,Map<String, List> advisorsCache,如下图所示: