AOP动态代理解析3-增强方法的获取
对于指定bean的增强方法的获取一定是包含两个步骤的:
- 获取所有的增强
- 寻找所有增强中使用于bean的增强并应用
那么findCandidateAdvisors与findAdvisorsThatCanApply便是做了这两件事情。当然,如果无法找到对应的增强器便返回DO_NOT_PROXY,其中DO_NOT_PROXY=null.
protected Object[] getAdvicesAndAdvisorsForBean(Class beanClass, String beanName, TargetSource targetSource) { List advisors = findEligibleAdvisors(beanClass, beanName); if(advisors.isEmpty()) return DO_NOT_PROXY; else return advisors.toArray(); } protected List findEligibleAdvisors(Class beanClass, String beanName) {
//获取所有的增强器 List candidateAdvisors = findCandidateAdvisors();
//获取适合beanname的增强器 List eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName); extendAdvisors(eligibleAdvisors); if(!eligibleAdvisors.isEmpty()) eligibleAdvisors = sortAdvisors(eligibleAdvisors); return eligibleAdvisors; }
所有增强器的获取
由于分析的是使用注解进行的AOP,所以对于findCandidateAdvisors的实现其实是由AnnotationAwareAspectJAutoProxyCreator类完成的,我们继续跟踪AnnotationAwareAspectJAutoProxyCreator的findCandidateAdvisors方法。
protected List findCandidateAdvisors() { //当使用注解方式配置AOP的时候并不是丢弃了对XML配置的支持。 //在这里调用父类方法加载配置文件中的AOP声明 List advisors = super.findCandidateAdvisors(); //Build Advisors for all AspectJ aspects in the bean factory advisors.addAll(aspectJAdvisorsBuilder.buildAspectJAdvisors()); return advisors; }
AnnotationAwareAspectJAutoProxyCreator间接继承了AbstractAdvisorAutoProxyCreator,在实现获取增强的方法中除了保留父类的获取配置文件中定义的增强外,同时添加了获取Bean的注解增强的功能,那么其实现正是由this.aspectJAdvisorsBuilder.buildAspectJAdvisors()来实现的。
(1)获取所有beanName,这一步骤中所有在beanFactory中注册的Bean都会被提取出来。
(2)遍历所有beanName,并找出声明AspectJ注解的类,进行进一步的处理。
(3)对标记为AspectJ注解的类进行增强器的提取。
(4)将提取结果加入缓存。
提取Advisor
现在来看看函数实现,对Spirng中所有的类进行分析,提取Advisor。
public List buildAspectJAdvisors() { List aspectNames = null; synchronized(this){ aspectNames = aspectBeanNames; if(aspectNames == null) { List advisors = new LinkedList(); aspectNames = new LinkedList(); //获取所有的beanName String beanNames[] = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory, java/lang/Object, true, false); //循环所有的beanName找出对应的增强方法 for(String beanName : beanNames) { //不合法的bean则略过,由子类定义规则,默认返回true if(!isEligibleBean(beanName)) continue; //获取对应的bean的类型 Class beanType = beanFactory.getType(beanName); //如果存在Aspect注解 if(beanType == null || !advisorFactory.isAspect(beanType)) continue; aspectNames.add(beanName); AspectMetadata amd = new AspectMetadata(beanType, beanName); MetadataAwareAspectInstanceFactory factory; if(amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) { factory = new BeanFactoryAspectInstanceFactory(beanFactory, beanName); //解析标记AspectJ注解中的增强方法 List classAdvisors = advisorFactory.getAdvisors(factory); if(beanFactory.isSingleton(beanName)) advisorsCache.put(beanName, classAdvisors); else aspectFactoryCache.put(beanName, factory); advisors.addAll(classAdvisors); continue; } if(beanFactory.isSingleton(beanName)) throw new IllegalArgumentException((
new StringBuilder()).append("Bean with name '")
.append(beanName)
.append("' is a singleton, but aspect instantiation model is not singleton")
.toString()); factory = new PrototypeAspectInstanceFactory(beanFactory, beanName); aspectFactoryCache.put(beanName, factory); advisors.addAll(advisorFactory.getAdvisors(factory)); } aspectBeanNames = aspectNames; return advisors; }
至此,已经完成了Advisor的提取。
切点信息的获取
在上面的步骤中最为重要也最为繁杂的就是增强器的获取,而这一切功能委托给了getAdvisors方法去实现(this.advisorFactory.getAdvisors(factory))。
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>(); 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方法实现,实现步骤包括对切点的注解的获取及根据注解信息生成增强。
(1)切点信息的获取。所谓获取切点信息就是指定注解的表达式信息的获取,如@Before("test()")
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; else //根据切点信息生成增强器 return new InstantiationModelAwarePointcutAdvisorImpl(this, ajexp, aif, candidateAdviceMethod, declarationOrderInAspect, aspectName); } 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*(..))")中的execution(* *.*test*(..)) ajexp.setExpression(aspectJAnnotation.getPointcutExpression()); return ajexp; } protected static AspectJAnnotation findAspectJAnnotationOnMethod(Method method) { //设置敏感的注解类 Class<? extends Annotation>[] classesToLookFor = new Class[] { Before.class, Around.class, After.class, AfterReturning.class, AfterThrowing.class, Pointcut.class}; for (Class<? extends Annotation> c : classesToLookFor) { AspectJAnnotation foundAnnotation = findAnnotation(method, 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实现类InstantiationModelAwarePontcutAdvisorImpl统一封装。
public InstantiationModelAwarePointcutAdvisorImpl(AspectJAdvisorFactory af, AspectJExpressionPointcut ajexp, MetadataAwareAspectInstanceFactory aif, Method method, int declarationOrderInAspect, String aspectName) { this.declaredPointcut = ajexp; this.method = method; this.atAspectJAdvisorFactory = af; this.aspectInstanceFactory = aif; this.declarationOrder = declarationOrderInAspect; this.aspectName = aspectName; if (aif.getAspectMetadata().isLazilyInstantiated()) { Pointcut preInstantiationPointcut = Pointcuts.union(aif.getAspectMetadata().getPerClausePointcut(), this.declaredPointcut); this.pointcut = new PerTargetInstantiationModelPointcut(this.declaredPointcut, preInstantiationPointcut, aif); this.lazy = true; } else { this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut); this.pointcut = declaredPointcut; this.lazy = false; } }
封装过程只是简单地将信息封装在类的实例中,所有的信息单纯地复制。在实例初始化的过程中还完成了对于增强器的初始化。因为不同的增强所体现的逻辑是不同的,比如@Before(“test()”)与After(“test()”)标签的不同就是增强器增强的位置不同,所以就需要不同的增强器来完成不同的逻辑,而根据注解中的信息初始化对应的增强器就是在instantiateAdvice函数中实现的。
private Advice instantiateAdvice(AspectJExpressionPointcut pcut) { return atAspectJAdvisorFactory.getAdvice(method, pcut, aspectInstanceFactory, declarationOrder, aspectName); } public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut ajexp,
MetadataAwareAspectInstanceFactory aif, int declarationOrderInAspect, String aspectName) { Class candidateAspectClass = aif.getAspectMetadata().getAspectClass(); validate(candidateAspectClass); AbstractAspectJAdvisorFactory.AspectJAnnotation aspectJAnnotation =
AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod); if(aspectJAnnotation == null) return null; if(!isAspect(candidateAspectClass)) throw new AopConfigException(
(new StringBuilder())
.append("Advice must be declared inside an aspect type: Offending method '")
.append(candidateAdviceMethod)
.append("' in class [")
.append(candidateAspectClass.getName())
.append("]").toString()); if(logger.isDebugEnabled()) logger.debug((new StringBuilder()).append("Found AspectJ method: ").append(candidateAdviceMethod).toString()); AbstractAspectJAdvice springAdvice; switch(SwitchMap.org.springframework.aop.aspectj.annotation.AbstractAspectJAdvisorFactory.AspectJAnnotationType
[aspectJAnnotation.getAnnotationType().ordinal()]) { case 1: // '\001' springAdvice = new AspectJMethodBeforeAdvice(candidateAdviceMethod, ajexp, aif); break; case 2: // '\002' springAdvice = new AspectJAfterAdvice(candidateAdviceMethod, ajexp, aif); break; case 3: // '\003' springAdvice = new AspectJAfterReturningAdvice(candidateAdviceMethod, ajexp, aif); AfterReturning afterReturningAnnotation = (AfterReturning)aspectJAnnotation.getAnnotation(); if(StringUtils.hasText(afterReturningAnnotation.returning())) springAdvice.setReturningName(afterReturningAnnotation.returning()); break; case 4: // '\004' springAdvice = new AspectJAfterThrowingAdvice(candidateAdviceMethod, ajexp, aif); AfterThrowing afterThrowingAnnotation = (AfterThrowing)aspectJAnnotation.getAnnotation(); if(StringUtils.hasText(afterThrowingAnnotation.throwing())) springAdvice.setThrowingName(afterThrowingAnnotation.throwing()); break; case 5: // '\005' springAdvice = new AspectJAroundAdvice(candidateAdviceMethod, ajexp, aif); break; case 6: // '\006' if(logger.isDebugEnabled()) logger.debug(
(new StringBuilder()).append("Processing pointcut '")
.append(candidateAdviceMethod.getName())
.append("'").toString()); return null; default: throw new UnsupportedOperationException(
(new StringBuilder()).append("Unsupported advice type on method ")
.append(candidateAdviceMethod).toString()); } springAdvice.setAspectName(aspectName); springAdvice.setDeclarationOrder(declarationOrderInAspect); String argNames[] = parameterNameDiscoverer.getParameterNames(candidateAdviceMethod); if(argNames != null) springAdvice.setArgumentNamesFromStringArray(argNames); springAdvice.calculateArgumentBindings(); return springAdvice; } }
从函数中可以看到,Spring会根据不同的注解生成不同的增强器,例如AtBefore会对应AspectJMethodBeforeAdvice。
增加同步实例化增强器
如果寻找的增强器不为空而且又配置了增强延迟初始化,那么就需要在首位加入同步实例化增强器。
protected static class SyntheticInstantiationAdvisor extends DefaultPointcutAdvisor { public SyntheticInstantiationAdvisor(final MetadataAwareAspectInstanceFactory aif) { super(aif.getAspectMetadata().getPerClausePointcut(), new MethodBeforeAdvice() { @Override public void before(Method method, Object[] args, Object target) { // Simply instantiate the aspect aif.getAspectInstance(); } }); } }
获取DeclareParents注解
DeclareParents主要用于引介增强的注解形式的实现,而其实现方式驭普通增强很类似,只不过使用DeclareParentsAdvisor对功能进行封装。
引介是一种特殊的增强,它为类添加一些属性和方法。这样,即使一个业务类原本没有实现某个接口,通过引介功能,可以动态的未该业务类添加接口的实现逻辑,让业务类成为这个接口的实现类。
private Advisor getDeclareParentsAdvisor(Field introductionField) { DeclareParents declareParents = (DeclareParents)introductionField.getAnnotation(org/aspectj/lang/annotation/DeclareParents); if(declareParents == null) return null; if("org/aspectj/lang/annotation/DeclareParents".equals(declareParents.defaultImpl())) throw new IllegalStateException("defaultImpl must be set on DeclareParents"); else return new DeclareParentsAdvisor(introductionField.getType(), declareParents.value(), declareParents.defaultImpl()); }
至此已经完成了所有增强器的解析,但是对于所有增强器来讲,并不一定都适用于当前的Bean,还要挑取除适合的增强器,也就是满足我们配置的通配符的增强器。具体的实现在findAdvisorsThatCanApply中。
获取合适的增强器
findAdvisorsThatCanApply函数的主要功能是寻找所有增强器中适用于当前class的增强器。对于真是的匹配在canApply中实现。
protected List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class beanClass, String beanName) { ProxyCreationContext.setCurrentProxiedBeanName(beanName); try { return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass); } finally { ProxyCreationContext.setCurrentProxiedBeanName(null); } } 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; } public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) { Assert.notNull(pc, "Pointcut must not be null"); if (!pc.getClassFilter().matches(targetClass)) { return false; } MethodMatcher methodMatcher = pc.getMethodMatcher(); IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null; if (methodMatcher instanceof IntroductionAwareMethodMatcher) { introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher; } Set<Class> classes = new LinkedHashSet<Class>(ClassUtils.getAllInterfacesForClassAsSet(targetClass)); classes.add(targetClass); for (Class<?> clazz : classes) { Method[] methods = clazz.getMethods(); for (Method method : methods) { if ((introductionAwareMethodMatcher != null && introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions)) || methodMatcher.matches(method, targetClass)) { return true; } } } return false; }