Spring AOP源码解读2 - 切面和增强的取得

前言

前一篇文章 中介绍了代理处理的入口,这一章介绍代理处理的流程之一:切面和增强的取得

正文

首先看看getAdvicesAndAdvisorsForBean方法的内容,这个方法的实现是在子类AbstractAdvisorAutoProxyCreator中完成的。这个方法里主要逻辑是在findEligibleAdvisors方法中:

protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, TargetSource targetSource) {
    List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
    if (advisors.isEmpty()) {
        return DO_NOT_PROXY;
    }
    return advisors.toArray();
}

findEligibleAdvisors中的主要逻辑是下面的这两个方法:

  1. findCandidateAdvisors:查找适合的Advisor(根据名字判断)
  2. findAdvisorsThatCanApply:看看Advisor能否被用在Bean上(根据Advisor的PointCut判断)
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
    // 查找适合的Advisor
    List<Advisor> candidateAdvisors = findCandidateAdvisors();
    // 看看Advisor能否被用在Bean上
    List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
    extendAdvisors(eligibleAdvisors);
    if (!eligibleAdvisors.isEmpty()) {
        eligibleAdvisors = sortAdvisors(eligibleAdvisors);
    }
    return eligibleAdvisors;
}

1,findCandidateAdvisors取得的相关流程:

关于findCandidateAdvisors方法,因为是分析AspectJ的相关的处理,所以我们看一下这个方法在AnnotationAwareAspectAutoProxyCreator类中的实现

protected List<Advisor> findCandidateAdvisors() {
    // Add all the Spring advisors found according to superclass rules.
    // 当使用注释方式配置 AOP 的时候并不是丢弃了对 XML 配置的支持。
    // 在这里调用父类方法加载配置文件中的 AOP 声明
    List<Advisor> advisors = super.findCandidateAdvisors();

    // Build Advisors for all AspectJ aspects in the bean factory.
    // 把BeanFactory里面的所有定义切面,定义成Spring中用的切面(Advisor),并放到集合里
    advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
    return advisors;
}
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>();

            // beanNamesForTypeIncludingAncestors方法是通过循环所有的bean,
            // 来取得所有指定类型的子类(这里指定的类型是Object,所以是所有类)
            // 实现是DefaultListableBeanFactory#doGetBeanNamesForType方法中
            // 判断子类是使用的Class#isAssignableFrom方法
            String[] beanNames =
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.beanFactory, Object.class, true, false);
            for (String beanName : beanNames) {
                // 根据Bean的名字,判断是否是适合
                // 这个方法根据实现类不同,实现方法也不同。
                // DefaultAdvisorAutoProxyCreator的话,判断方法内部,!isUsePrefix()永远返回True,所以这个判断总是True
                // 具体的类型的判断是使用AbstractBeanFactory#isTypeMatch方法
                if (!isEligibleBean(beanName)) {
                    continue;
                }
                // We must be careful not to instantiate beans eagerly as in this
                // case they would be cached by the Spring container but would not
                // have been weaved
                // 获取对应的 bean 的类型
                Class<?> beanType = this.beanFactory.getType(beanName);
                if (beanType == null) {
                    continue;
                }

                // 如果beanType是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);

                        // 读取Aspect类的方法上的注解,从而生成Advisors。
                        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 {
                        // Per target or per this.
                        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 接口的继承关系,在 ReflectiveAspectJAdvisorFactory 类中找到了他的 getAdvisors 实现类。

public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory maaif) {
    final Class<?> aspectClass = maaif.getAspectMetadata().getAspectClass();
    final String aspectName = maaif.getAspectMetadata().getAspectName();
    validate(aspectClass);

    // We need to wrap the MetadataAwareAspectInstanceFactory with a decorator
    // so that it will only instantiate once.
    final MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
            new LazySingletonAspectInstanceFactoryDecorator(maaif);

    final List<Advisor> advisors = new LinkedList<Advisor>();
    // 对aspectClass的每一个带有注解的方法进行循环(带有PointCut注解的方法除外),取得Advisor,并添加到集合里。
    // (这是里应该是取得Advice,然后取得我们自己定义的切面类中PointCut,组合成Advisor)
    for (Method method : getAdvisorMethods(aspectClass)) {
        Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, advisors.size(), aspectName);
        if (advisor != null) {
            advisors.add(advisor);
        }
    }

    // If it's a per target aspect, emit the dummy instantiating aspect.
    if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
        Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);
        advisors.add(0, instantiationAdvisor);
    }

    // Find introduction fields.
    // 查找引入增强,并加到集合中。
    for (Field field : aspectClass.getDeclaredFields()) {
        Advisor advisor = getDeclareParentsAdvisor(field);
        if (advisor != null) {
            advisors.add(advisor);
        }
    }

    return advisors;
}
// 这个方法,通过很巧妙的使用接口,定义一个匿名回调,把带有注解的Method都取得出来,放到集合里,有兴趣可以看看。
private List<Method> getAdvisorMethods(Class<?> aspectClass) {
    final List<Method> methods = new LinkedList<Method>();
    ReflectionUtils.doWithMethods(aspectClass, new ReflectionUtils.MethodCallback() {
        @Override
        public void doWith(Method method) throws IllegalArgumentException {
            // Exclude pointcuts
            if (AnnotationUtils.getAnnotation(method, Pointcut.class) == null) {
                methods.add(method);
            }
        }
    });
    Collections.sort(methods, METHOD_COMPARATOR);
    return methods;
}

普通增强器的获取逻辑通过 getAdvisor 方法来实现,实现步骤包括对切点的注解以及根据注解信息生成增强。

public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aif,
        int declarationOrderInAspect, String aspectName) {

    validate(aif.getAspectMetadata().getAspectClass());
    // 获取PointCut信息(主要是PointCut里的表达式)
    // 把Method对象也传进去的目的是,比较Method对象上的注解,是不是下面注解其中一个
    // 如果不是,返回null;如果是,就把取得PointCut内容包装返回
    // 被比较注解:Before.class, Around.class, After.class, AfterReturning.class, AfterThrowing.class, Pointcut.class
    AspectJExpressionPointcut ajexp =
            getPointcut(candidateAdviceMethod, aif.getAspectMetadata().getAspectClass());
    if (ajexp == null) {
        return null;
    }
    // 根据PointCut信息生成增强器
    return new InstantiationModelAwarePointcutAdvisorImpl(
            this, ajexp, aif, candidateAdviceMethod, declarationOrderInAspect, aspectName);
}
private AspectJExpressionPointcut getPointcut(Method candidateAdviceMethod, Class<?> candidateAspectClass) {
    // 获取方法上的注解
    // 比较Method对象上的注解,是不是下面注解其中一个,如果不是返回null
    // 被比较注解:Before.class, Around.class, After.class, AfterReturning.class, AfterThrowing.class, Pointcut.class
    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;
}
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;
    }
}

上面的getAdvisor方法的最后一行代码是
return new InstantiationModelAwarePointcutAdvisorImpl(
this, ajexp, aif, candidateAdviceMethod, declarationOrderInAspect, aspectName)

这行代码作用是根据切点信息生成增强。所有的增强都由 Advisor 的实现类InstantiationModelAwarePointcutAdvisorImpl 统一封装的。

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()) {
        // Static part of the pointcut is a lazy type.
        Pointcut preInstantiationPointcut =
                Pointcuts.union(aif.getAspectMetadata().getPerClausePointcut(), this.declaredPointcut);

        // Make it dynamic: must mutate from pre-instantiation to post-instantiation state.
        // If it's not a dynamic pointcut, it may be optimized out
        // by the Spring AOP infrastructure after the first evaluation.
        this.pointcut = new PerTargetInstantiationModelPointcut(this.declaredPointcut, preInstantiationPointcut, aif);
        this.lazy = true;
    }
    else {
        // A singleton aspect.
        // 初始化Advice
        this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut);
        this.pointcut = declaredPointcut;
        this.lazy = false;
    }
}

在封装过程中只是简单地将信息封装在类的实例中而已,所有的信息单纯地赋值,在实例初始化的过程中还完成了对于增强器的初始化。因为不同的增强所体现的逻辑是不同的,而根据注解中的信息初始化对应的增强器是在 instantiateAdvice 方法中完成的。

private Advice instantiateAdvice(AspectJExpressionPointcut pcut) {
    return this.atAspectJAdvisorFactory.getAdvice(
        this.method, pcut, this.aspectInstanceFactory, this.declarationOrder, this.aspectName);
}
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);
}

2,findAdvisorsThatCanApply相关流程

findCandidateAdvisors通过名字匹配,找到了一些适合的Advisor,我们再来看看findAdvisorsThatCanApply方法。这个方法是作用就是根据PointCut,看目标类是不是符合代理对象的条件,如果符合就把Advisor加到集合中,最后返回集合。

public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
    if (candidateAdvisors.isEmpty()) {
        return candidateAdvisors;
    }
    List<Advisor> eligibleAdvisors = new LinkedList<Advisor>();
    // 这个循环主要是处理IntroductionAdvisor类型的Advisor,看适合不适合
    for (Advisor candidate : candidateAdvisors) {
        if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
            eligibleAdvisors.add(candidate);
        }
    }
    boolean hasIntroductions = !eligibleAdvisors.isEmpty();
    // 这个循环处理非IntroductionAdvisor类型的Advisor
    for (Advisor candidate : candidateAdvisors) {
        if (candidate instanceof IntroductionAdvisor) {
            // already processed
            continue;
        }
        // 在这里判断是否适合
        if (canApply(candidate, clazz, hasIntroductions)) {
            eligibleAdvisors.add(candidate);
        }
    }
    return eligibleAdvisors;
}

   // 根据Advisor类型不同,判断方法也不同,我们看一下最常用的PointCut类型
public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {
    if (advisor instanceof IntroductionAdvisor) {
        return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass);
    }
    // PointCut类型的Advisor的判断方法
    else if (advisor instanceof PointcutAdvisor) {
        PointcutAdvisor pca = (PointcutAdvisor) advisor;
        return canApply(pca.getPointcut(), targetClass, hasIntroductions);
    }
    else {
        // It doesn't have a pointcut so we assume it applies.
        return true;
    }
}
// 看了实现方式,判断方式就是通过PointCut进行判断的
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;
}

到此为止,切面和增强的取得相关逻辑讲完了,下一章讲解如何使用找到切面,来创建代理。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值