上文中已经提到了获取指定加强方法的两个步骤:(1)获取全部的加强,(2)寻找全部加强中适用于 bean 的加强并应用,而这两个步骤是由 findCandidateAdvisors 和 findAdvisorsThatCanApply 来完成的。下图是相关的时序图:java
但在介绍源码前,我必须先了解一下加强以及其相关逻辑。ios
好了,让咱们从新回到源码分析,值得注意的是 咱们分析的是使用注释的 AOP,咱们对于 findCandidateAdvisors 方法的实现进行追踪,在 AnnotationAwareAspectAutoProxyCreator 中发现了他的实现方法。
web
AnnotationAwareAspectAutoProxyCreator.javaspring
@Override protected List<Advisor> findCandidateAdvisors() { // 当使用注释方式配置 AOP 的时候并非丢弃了对 XML 配置的支持。 // 在这里调用父类方法加载配置文件中的 AOP 声明 List<Advisor> advisors = super.findCandidateAdvisors(); // Build Advisors for all AspectJ aspects in the bean factory. advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors()); return advisors; }
而在 AnnotationAwareAspectAutoProxyCreator 的 findAdvisorBeans 方法里间接继承了 AbstractAutoProxyCreator 中的 findAdvisorBeans 方法,在实现中除了保留父类的获取配置文件中定义的加强外,同时添加了获取 Bean 的注解加强的功能,而真正实现是由 this.aspectJAdvisorsBuilder.buildAspectJAdvisors()来实现的。缓存
看下代码,咱们就能明白其中的思路。首先,获取全部在 beanFacotry 中注册的 Bean 都会被提取出来。而后遍历全部 beanName,并找出声明 AspectJ 注释的类,进一步处理。最后,将将结果加入缓存。
ide
BeanFactoryAspectJAdvisorsBuilder.java函数
public List<Advisor> buildAspectJAdvisors() { List<String> aspectNames = null; synchronized (this) { aspectNames = this.aspectBeanNames; if (aspectNames == null) { List<Advisor> advisors = new LinkedList<Advisor>(); aspectNames = new LinkedList<String>(); // 获取全部的 beanName String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.beanFactory, Object.class, true, false); // 循环全部的 beanName 找出对应的加强方法 for (String beanName : beanNames) { // 不合法的 bean 则略过,由子类定义规则,默认返回 true if (!isEligibleBean(beanName)) { continue; } // 获取对应的 bean 的类型 Class<?> beanType = this.beanFactory.getType(beanName); if (beanType == null) { continue; } // 若是存在 Aspect 注解 if (this.advisorFactory.isAspect(beanType)) { aspectNames.add(beanName); AspectMetadata amd = new AspectMetadata(beanType, beanName); if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) { MetadataAwareAspectInstanceFactory factory = new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName); // 解析标记 AspectJ 注解的加强方法 List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory); if (this.beanFactory.isSingleton(beanName)) { this.advisorsCache.put(beanName, classAdvisors); } else { this.aspectFactoryCache.put(beanName, factory); } advisors.addAll(classAdvisors); } else { if (this.beanFactory.isSingleton(beanName)) { throw new IllegalArgumentException("Bean with name '" + beanName + "' is a singleton, but aspect instantiation model is not singleton"); } MetadataAwareAspectInstanceFactory factory = new PrototypeAspectInstanceFactory(this.beanFactory, beanName); this.aspectFactoryCache.put(beanName, factory); advisors.addAll(this.advisorFactory.getAdvisors(factory)); } } } this.aspectBeanNames = aspectNames; return advisors; } } if (aspectNames.isEmpty()) { return Collections.emptyList(); } // 记录在缓存中 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; }
至此,咱们已经完成了通知器的解析。往下咱们就介绍最重要的也是最繁琐的通知器的获取。源码分析
在上面的步骤中最为重要也最为繁琐的就是通知器的获取。而这一功能看源码,是由 AspectJAdviosrFactory 接口的 getAdvisors 方法来完成的,下图是 AspectJAdviosrFactory 的继承关系图:ui
咱们根据 AspectJAdviosrFactory 接口的继承关系,在 ReflectiveAspectJAdvisorFactory 类中找到了他的 getAdvisors 实现类。this
ReflectiveAspectJAdvisorFactory.java
public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory maaif) { // 获取标记为 AspectJ 的类 final Class<?> aspectClass = maaif.getAspectMetadata().getAspectClass(); // 获取标记为 AspectJ 的name final String aspectName = maaif.getAspectMetadata().getAspectName(); // 验证 validate(aspectClass); final MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory = new LazySingletonAspectInstanceFactoryDecorator(maaif); final List<Advisor> advisors = new LinkedList<Advisor>(); // 声明为 Pointcut 的方法不处理 for (Method method : getAdvisorMethods(aspectClass)) { Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, advisors.size(), aspectName); if (advisor != null) { advisors.add(advisor); } } if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) { // 若是寻找的加强器不为空并且又配置了加强延迟初始化那么须要在首位加入同步实例化加强器 Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory); advisors.add(0, instantiationAdvisor); } // 获取 DeclareParents 注解 for (Field field : aspectClass.getDeclaredFields()) { Advisor advisor = getDeclareParentsAdvisor(field); if (advisor != null) { advisors.add(advisor); } } return advisors; }
函数中首先完成了对加强器的获取,包括获取注解以及根据注解生成加强的步骤,而后考虑到在配置中可能会将加强配置成延迟初始化,那么须要在首位加入同步实例化加强以保证加强使用以前的实例化,最后对 DeclareParents 注解的获取,下面将详细介绍一下每一个步骤。
普通加强器的获取逻辑经过 getAdvisor 方法来实现,实现步骤包括对切点的注解以及根据注解信息生成加强。
ReflectiveAspectJAdvisorFactory.java
@Override public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aif, int declarationOrderInAspect, String aspectName) { validate(aif.getAspectMetadata().getAspectClass()); // 切点信息的获取 AspectJExpressionPointcut ajexp = getPointcut(candidateAdviceMethod, aif.getAspectMetadata().getAspectClass()); if (ajexp == null) { return null; } // 根据切点信息生成加强器 return new InstantiationModelAwarePointcutAdvisorImpl( this, ajexp, aif, candidateAdviceMethod, declarationOrderInAspect, aspectName); }
(1)切点信息的获取。所谓获取切点信息就是指定注解的表达式信息的获取,如@Before("test()")。
ReflectiveAspectJAdvisorFactory.java
private AspectJExpressionPointcut getPointcut(Method candidateAdviceMethod, Class<?> candidateAspectClass) { // 获取方法上的注解 AspectJAnnotation<?> aspectJAnnotation = AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod); if (aspectJAnnotation == null) { return null; } // 使用AspectJExpressionPointcut 实例封装获取的信息 AspectJExpressionPointcut ajexp = new AspectJExpressionPointcut(candidateAspectClass, new String[0], new Class<?>[0]); // 提取获得的注解中的表达式如: // @Pointcut("execution(* test.TestBean.*(..))") ajexp.setExpression(aspectJAnnotation.getPointcutExpression()); return ajexp; }
AbstractAspectJAdvisorFactory.java
protected static AspectJAnnotation<?> findAspectJAnnotationOnMethod(Method method) { // 设置敏感的注解类 Class<?>[] classesToLookFor = new Class<?>[] { Before.class, Around.class, After.class, AfterReturning.class, AfterThrowing.class, Pointcut.class}; for (Class<?> c : classesToLookFor) { AspectJAnnotation<?> foundAnnotation = findAnnotation(method, (Class<Annotation>) c); if (foundAnnotation != null) { return foundAnnotation; } } return null; } // 获取指定方法上的注解并使用 AspectJAnnotation 封装 private static <A extends Annotation> AspectJAnnotation<A> findAnnotation(Method method, Class<A> toLookFor) { A result = AnnotationUtils.findAnnotation(method, toLookFor); if (result != null) { return new AspectJAnnotation<A>(result); } else { return null; } }
(2)根据切点信息生成加强。全部的加强都由 Advisor 的实现类 InstantiationModelAwarePointcutAdvisorImpl 统一封装的。
InstantiationModelAwarePointcutAdvisorImpl.java
public InstantiationModelAwarePointcutAdvisorImpl(AspectJAdvisorFactory af, AspectJExpressionPointcut ajexp, MetadataAwareAspectInstanceFactory aif, Method method, int declarationOrderInAspect, String aspectName) { // test() this.declaredPointcut = ajexp; // public void test.AspectJTest.beforeTest() this.method = method; this.atAspectJAdvisorFactory = af; this.aspectInstanceFactory = aif; this.declarationOrder = declarationOrderInAspect; this.aspectName = aspectName; if (aif.getAspectMetadata().isLazilyInstantiated()) { // Static part of the pointcut is a lazy type. Pointcut preInstantiationPointcut = Pointcuts.union(aif.getAspectMetadata().getPerClausePointcut(), this.declaredPointcut); this.pointcut = new PerTargetInstantiationModelPointcut(this.declaredPointcut, preInstantiationPointcut, aif); this.lazy = true; } else { // A singleton aspect. this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut); this.pointcut = declaredPointcut; this.lazy = false; } }
在封装过程当中只是简单地将信息封装在类的实例中而已,全部的信息单纯地赋值,在实例初始化的过程当中还完成了对于加强器的初始化。由于不一样的加强所体现的逻辑是不一样的,而根据注解中的信息初始化对应的加强器是在 instantiateAdvice 方法中完成的。
InstantiationModelAwarePointcutAdvisorImpl.java
private Advice instantiateAdvice(AspectJExpressionPointcut pcut) { return this.atAspectJAdvisorFactory.getAdvice( this.method, pcut, this.aspectInstanceFactory, this.declarationOrder, this.aspectName); }
而与 AspectJAdviosrFactory 接口的 getAdvisors 方法同样,getAdvice 方法也是在 ReflectiveAspectJAdvisorFactory 类中完成的。
ReflectiveAspectJAdvisorFactory.java
@Override public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut ajexp, MetadataAwareAspectInstanceFactory aif, int declarationOrderInAspect, String aspectName) { Class<?> candidateAspectClass = aif.getAspectMetadata().getAspectClass(); validate(candidateAspectClass); AspectJAnnotation<?> aspectJAnnotation = AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod); if (aspectJAnnotation == null) { return null; } // If we get here, we know we have an AspectJ method. // Check that it's an AspectJ-annotated class if (!isAspect(candidateAspectClass)) { throw new AopConfigException("Advice must be declared inside an aspect type: " + "Offending method '" + candidateAdviceMethod + "' in class [" + candidateAspectClass.getName() + "]"); } if (logger.isDebugEnabled()) { logger.debug("Found AspectJ method: " + candidateAdviceMethod); } AbstractAspectJAdvice springAdvice; // 根据不一样的注解类封装加强器 switch (aspectJAnnotation.getAnnotationType()) { case AtBefore: springAdvice = new AspectJMethodBeforeAdvice(candidateAdviceMethod, ajexp, aif); break; case AtAfter: springAdvice = new AspectJAfterAdvice(candidateAdviceMethod, ajexp, aif); break; case AtAfterReturning: springAdvice = new AspectJAfterReturningAdvice(candidateAdviceMethod, ajexp, aif); AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation(); if (StringUtils.hasText(afterReturningAnnotation.returning())) { springAdvice.setReturningName(afterReturningAnnotation.returning()); } break; case AtAfterThrowing: springAdvice = new AspectJAfterThrowingAdvice(candidateAdviceMethod, ajexp, aif); AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation(); if (StringUtils.hasText(afterThrowingAnnotation.throwing())) { springAdvice.setThrowingName(afterThrowingAnnotation.throwing()); } break; case AtAround: springAdvice = new AspectJAroundAdvice(candidateAdviceMethod, ajexp, aif); break; case AtPointcut: if (logger.isDebugEnabled()) { logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'"); } return null; default: throw new UnsupportedOperationException( "Unsupported advice type on method " + candidateAdviceMethod); } // Now to configure the advice... springAdvice.setAspectName(aspectName); springAdvice.setDeclarationOrder(declarationOrderInAspect); String[] argNames = this.parameterNameDiscoverer.getParameterNames(candidateAdviceMethod); if (argNames != null) { springAdvice.setArgumentNamesFromStringArray(argNames); } springAdvice.calculateArgumentBindings(); return springAdvice; }
从函数中,咱们能够看出,Spring 会根据不一样的注解生成不一样的加强器,由于太过庞杂了,这里就不先讲述了,笔者会在后面介绍设计方法的时候慢慢讲述的。
若是寻找的加强器不为空并且又配置了加强延迟初始化,那么就须要在首位加入同步实例化加强器,具体实现以下:
ReflectiveAspectJAdvisorFactory.java
protected static class SyntheticInstantiationAdvisor extends DefaultPointcutAdvisor { public SyntheticInstantiationAdvisor(final MetadataAwareAspectInstanceFactory aif) { super(aif.getAspectMetadata().getPerClausePointcut(), new MethodBeforeAdvice() { // 目标方法前调用,相似@Before @Override public void before(Method method, Object[] args, Object target) { // 简单初始化 aspect aif.getAspectInstance(); } }); } }
DeclareParents 主要用于引介加强的注解形式的实现,而其实现方式与普通加强很相似,只是作了封装。
ReflectiveAspectJAdvisorFactory.java
private Advisor getDeclareParentsAdvisor(Field introductionField) { DeclareParents declareParents = introductionField.getAnnotation(DeclareParents.class); if (declareParents == null) { // Not an introduction field return null; } if (DeclareParents.class.equals(declareParents.defaultImpl())) { // This is what comes back if it wasn't set. This seems bizarre... // TODO this restriction possibly should be relaxed throw new IllegalStateException("defaultImpl must be set on DeclareParents"); } return new DeclareParentsAdvisor( introductionField.getType(), declareParents.value(), declareParents.defaultImpl()); }
前面的函数中已经完成了全部的加强的解析,但对于全部加强来说,并不必定都适用于当前的 Bean,还要挑选出适合的加强,也就是知足咱们配置的通配符的加强器。具体实如今 findAdvisorsThatCanApply 中,并且 findAdvisorsThatCanApply 也比上面来的简单的多。
AbstractAdvisorAutoProxyCreator.java
protected List<Advisor> findAdvisorsThatCanApply( List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) { ProxyCreationContext.setCurrentProxiedBeanName(beanName); try { // 过滤已经获得的 advisors return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass); } finally { ProxyCreationContext.setCurrentProxiedBeanName(null); } }
继续看 findAdvisorsThatCanApply:
AopUtils.java
public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) { if (candidateAdvisors.isEmpty()) { return candidateAdvisors; } List<Advisor> eligibleAdvisors = new LinkedList<Advisor>(); // 首先处理引介加强 for (Advisor candidate : candidateAdvisors) { if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) { eligibleAdvisors.add(candidate); } } boolean hasIntroductions = !eligibleAdvisors.isEmpty(); for (Advisor candidate : candidateAdvisors) { // 引介加强已经处理 if (candidate instanceof IntroductionAdvisor) { continue; } // 对于普通 bean 的处理 if (canApply(candidate, clazz, hasIntroductions)) { eligibleAdvisors.add(candidate); } } return eligibleAdvisors; }
findAdvisorsThatCanApply 函数的主要功能是寻找全部加强器中适合于当前 class 的加强器。引介加强与普通的加强是处理不同的,因此分开处理。而对于真正的匹配在 canApply 中实现。
AopUtils.java
public static boolean canApply(Advisor advisor, Class<?> targetClass) { return canApply(advisor, targetClass, false); } public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) { if (advisor instanceof IntroductionAdvisor) { return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass); } else if (advisor instanceof PointcutAdvisor) { PointcutAdvisor pca = (PointcutAdvisor) advisor; return canApply(pca.getPointcut(), targetClass, hasIntroductions); } else { return true; } }
至此,getAdvicesAndAdvisorsForBean 方法要作的事就完成了,接下来就是 createProxy 方法生成代理了。
——水门(2016年3月于杭州)