33--SpringAop获取增强

版权声明:如有转载,请标明出处,谢谢合作! https://blog.csdn.net/lyc_liyanchao/article/details/83782330

上一节分析了aspectj-autoproxy标签的解析过程,并完成了AnnotationAwareAspectJAutoProxyCreator的注册。但是该类的作用是什么呢,看起来茫然无措,这时不妨查看一下类的继承关系结构。

AnnotationAwareAspectJAutoProxyCreator类图结构

从上图可以看到,AnnotationAwareAspectJAutoProxyCreator类实现了BeanPostProcessor接口,读过之前的章节或者对bean的生命周期有所了解的同学一定知道,在bean实例化完成之前和完成之后分别会自动BeanPostProcessor接口的postProcessBeforeInitialization和postProcessAfterInitialization方法。

依次打开AnnotationAwareAspectJAutoProxyCreator的父类,在AbstractAutoProxyCreator类里,找到postProcessBeforeInitialization方法和postProcessAfterInitialization方法,开始分析。

1. postProcessBeforeInstantiation方法
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
    Object cacheKey = getCacheKey(beanClass, beanName);

    // 1、预处理判断
    if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
        // 判断该类是否应被处理过
        if (this.advisedBeans.containsKey(cacheKey)) {
            return null;
        }
        // 判断beanClass是否需要被代理,if判断条件如果满足的话,则说明该类是一个切面类,缓存该类信息
        // isInfrastructureClass-->判断beanClass是否为AOP基础类例如Advice,Pointcut或者是一个切面类
        // shouldSkip-->判断beanClass是否指定了不需要代理
        if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
        	// 缓存找到的切面类信息
            this.advisedBeans.put(cacheKey, Boolean.FALSE);	
            return null;
        }
    }

    // Create proxy here if we have a custom TargetSource.
    // Suppresses unnecessary default instantiation of the target bean:
    // The TargetSource will handle target instances in a custom fashion.
    // 2、如果有自定义TargetSource的话,则在此创建代理
    TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
    if (targetSource != null) {
        if (StringUtils.hasLength(beanName)) {
            this.targetSourcedBeans.add(beanName);
        }
        Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
        Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
        this.proxyTypes.put(cacheKey, proxy.getClass());
        return proxy;
    }

    return null;
}

postProcessBeforeInstantiation一共做了两件事情

  1. 缓存切面类的信息
    先判断对应的beanClass是否为Aop的基础类,如果是的话,直接缓存。
    然后通过shouldSkip方法判断beanClass是否需要被自动代理,如果不需要被自动代理的话,返回true,否则返回false。
  2. 判断有无自定义TargetSource,如果有的话,则在此方法里创建代理
    关于自定义TargetSource在下面的篇幅介绍,这里我们还是要梳理主流程,不要被分支困扰。
2.postProcessAfterInitialization方法简析
/**
 * 如果bean被子类标识为要代理的bean,则使用配置的拦截器创建代理。
 * Create a proxy with the configured interceptors if the bean is
 * identified as one to proxy by the subclass.
 * @see #getAdvicesAndAdvisorsForBean
 */
@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
    if (bean != null) {
        // 为beanName和beanClass构建缓存key
        Object cacheKey = getCacheKey(bean.getClass(), beanName);
        if (!this.earlyProxyReferences.contains(cacheKey)) {
            // 包装bean
            return wrapIfNecessary(bean, beanName, cacheKey);
        }
    }
    return bean;
}

从方法注释上可以看到,创建代理的逻辑的就在该方法中。

  • wrapIfNecessary方法分析
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
    // 1、如果已经处理过或者不需要创建代理,则返回
    if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
        return bean;
    }
    if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
        return bean;
    }
    if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
        this.advisedBeans.put(cacheKey, Boolean.FALSE);
        return bean;
    }

    // 2、创建代理
    Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
    if (specificInterceptors != DO_NOT_PROXY) {
        this.advisedBeans.put(cacheKey, Boolean.TRUE);
        Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
        this.proxyTypes.put(cacheKey, proxy.getClass());
        return proxy;
    }

    // 3、缓存
    this.advisedBeans.put(cacheKey, Boolean.FALSE);
    return bean;
}

在这里又看到了Spring处理复杂逻辑的一贯套路,预置处理、执行真正业务方法、缓存结果。

  1. 如果已经处理过或者不需要创建代理,则返回
  2. 创建代理
  3. 缓存
    从上面的分析可以得到创建代理分为了两个步骤:获取增强和创建代理,下面我们逐步分析这两个步骤:
3.获取增强
/**
 * 获取指定bean的增强和增强器
 * @param beanClass the class of the bean to advise
 * @param beanName the name of the bean
 * @param targetSource
 * @return
 */
@Override
@Nullable
protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
    // 获取符合条件的增强并返回
    List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
    if (advisors.isEmpty()) {
        return DO_NOT_PROXY;
    }
    return advisors.toArray();
}
/**
 * 为当前bean获取所有需要自动代理的增强
 * Find all eligible Advisors for auto-proxying this class.
 * @param beanClass the clazz to find advisors for
 * @param beanName the name of the currently proxied bean
 * @return the empty List, not {@code null},
 * if there are no pointcuts or interceptors
 * @see #findCandidateAdvisors
 * @see #sortAdvisors
 * @see #extendAdvisors
 */
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
    // 1、查找所有候选增强方法
    List<Advisor> candidateAdvisors = findCandidateAdvisors();
    // 2、从给定的增强中找出可以应用到当前指定bean的增强
    List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
    // 3、在eligibleAdvisors集合首位加入ExposeInvocationInterceptor增强
    extendAdvisors(eligibleAdvisors);
    // 4、排序
    if (!eligibleAdvisors.isEmpty()) {
        eligibleAdvisors = sortAdvisors(eligibleAdvisors);
    }
    return eligibleAdvisors;
}

findEligibleAdvisors方法一共执行了四个步骤,我们关心的是前两个步骤:

  • 查找所有候选增强方法
/**
 * 查找所有候选增强方法
 * @return
 */
@Override
protected List<Advisor> findCandidateAdvisors() {
    // Add all the Spring advisors found according to superclass rules.
    // 1、从父类中获取所有的增强
    List<Advisor> advisors = super.findCandidateAdvisors();
    // Build Advisors for all AspectJ aspects in the bean factory.
    // 2、从当前BeanFactory中查找所有标记了@AspectJ的注解的bean,并返回增强注解集合
    if (this.aspectJAdvisorsBuilder != null) {
        advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
    }
    return advisors;
}

由于我们没有设置父BeanFactory所以super.findCandidateAdvisors();会返回一个空的集合(该方不会返回null),那么接下来就要再当前BeanFactory中查找增强了。即通过this.aspectJAdvisorsBuilder.buildAspectJAdvisors()查找。

/**
 * 在当前BeanFactory中查找AspectJ-annotated的注解信息,并返回增强集合
 * Look for AspectJ-annotated aspect beans in the current bean factory,
 * and return to a list of Spring AOP Advisors representing them.
 * <p>Creates a Spring Advisor for each AspectJ advice method.
 * @return the list of {@link org.springframework.aop.Advisor} beans
 * @see #isEligibleBean
 */
public List<Advisor> buildAspectJAdvisors() {
    List<String> aspectNames = this.aspectBeanNames;

    // 1、提取增强
    if (aspectNames == null) {
        synchronized (this) {
            aspectNames = this.aspectBeanNames;
            if (aspectNames == null) {
                List<Advisor> advisors = new ArrayList<>();
                aspectNames = new ArrayList<>();
                // 1.1、获取容器中的所有bean
                String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
                        this.beanFactory, Object.class, true, false);
                // 1.2、循环所有的bean,并从切面类上提取增强方法
                for (String beanName : beanNames) {

                    // 判断该beanName是否符合条件
                    // 如果配置文件指定了<aop:include/>属性,那么只有符合表达式条件的切面类的增强才会被提取
                    // 例如:配置<aop:include name="dogAspect"></aop:include>
                    // 那么只有dogAspect切面类的增强才会被提取
                    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.
                    // 获取beanType类型
                    Class<?> beanType = this.beanFactory.getType(beanName);
                    if (beanType == null) {
                        continue;
                    }
                    // 如果beanType是一个切面类
                    if (this.advisorFactory.isAspect(beanType)) {
                        aspectNames.add(beanName);
                        AspectMetadata amd = new AspectMetadata(beanType, beanName);
                        /**
                         * 切面实例化模型简介
                         *
                         * singleton: 即切面只会有一个实例;
                         * perthis  : 每个切入点表达式匹配的连接点对应的AOP对象都会创建一个新切面实例;
                         *            使用@Aspect("perthis(切入点表达式)")指定切入点表达式;
                         *            例如: @Aspect("perthis(this(com.lyc.cn.v2.day04.aspectj.Dog))")
                         * pertarget: 每个切入点表达式匹配的连接点对应的目标对象都会创建一个新的切面实例;
                         *            使用@Aspect("pertarget(切入点表达式)")指定切入点表达式;
                         *            例如:
                         *
                         * 默认是singleton实例化模型,Schema风格只支持singleton实例化模型,而@AspectJ风格支持这三种实例化模型。
                         */
                        // singleton实例化模型处理
                        if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
                            MetadataAwareAspectInstanceFactory factory = new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
                            // 获取所有的增强方法,并缓存
                            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);
                        }
                        // perthis或pertarget实例化模型处理
                        else {
                            /**
                             * 注意:当使用perthis或pertarget属性时,切面类不能是单例bean,否则会抛出下面的异常
                             * 例如:<bean name="dogAspect" class="com.lyc.cn.v2.day04.aspectj.DogAspect" scope="singleton"/>
                             * 则会报错,应该为
                             *      <bean name="dogAspect" class="com.lyc.cn.v2.day04.aspectj.DogAspect" scope="prototype"/>
                             */
                            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;
            }
        }
    }

    // 2、返回从缓存中获取提取到的增强方法
    if (aspectNames.isEmpty()) {
        return Collections.emptyList();
    }
    List<Advisor> advisors = new ArrayList<>();
    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;
}

其中的步骤在代码里都标注的很清晰了,这里会涉及到一个切面实例化模型的概念,如果初看AOP的源码,完全可以忽略该概念,把精力放在主线的分析上。其实该方法里大部分都是预处理、缓存、以及各种业务判断,增强的提取工作交给了List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);。看一下该方法是如何提取增强的:

@Override
public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
    // 1、预处理工作,包括获取切面类,名称,验证等
    Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
    String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();
    validate(aspectClass);

    // 我们需要用一个装饰器包装MetadataAwareAspectInstanceFactory,这样它只会实例化一次。
    MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
            new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);

    // 2、提取增强
    // 2.1、获取切面类的所有方法,循环判断提取合适的切入点,并创建增强
    List<Advisor> advisors = new ArrayList<>();
    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.
    // 2.2、处理perthis和pertarget切面类
    if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
        // 创建SyntheticInstantiationAdvisor实例
        Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);
        // 将SyntheticInstantiationAdvisor实例加入到advisors集合首位,注意:不是替换
        advisors.add(0, instantiationAdvisor);
    }

    // Find introduction fields.
    // 2.3、处理引入,获取所有的引入并循环创建DeclareParentsAdvisor
    for (Field field : aspectClass.getDeclaredFields()) {
        Advisor advisor = getDeclareParentsAdvisor(field);
        if (advisor != null) {
            advisors.add(advisor);
        }
    }

    return advisors;
}

在该方法中提取工作一共分为了三步:提取普通增强、处理处理perthis和pertarget、引介增强。篇幅有限,只分析普通增强的处理过程:

@Override
@Nullable
public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
        int declarationOrderInAspect, String aspectName) {

    // 1、验证
    validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());

    // 2、提取切入点
    AspectJExpressionPointcut expressionPointcut = getPointcut(
            candidateAdviceMethod,
            aspectInstanceFactory.getAspectMetadata().getAspectClass());

    if (expressionPointcut == null) {
        return null;
    }

    // 3、创建增强
    return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
            this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
}

代码执行到第二步已经可以提取到切入点,接下来单开一个小节看一下增强的创建过程。

4.创建增强

上面的分析已经成功得到了切入点,接下来看增强创建的过程:

public InstantiationModelAwarePointcutAdvisorImpl(AspectJExpressionPointcut declaredPointcut,
			Method aspectJAdviceMethod, AspectJAdvisorFactory aspectJAdvisorFactory,
			MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {

    this.declaredPointcut = declaredPointcut;
    this.declaringClass = aspectJAdviceMethod.getDeclaringClass();
    this.methodName = aspectJAdviceMethod.getName();
    this.parameterTypes = aspectJAdviceMethod.getParameterTypes();
    this.aspectJAdviceMethod = aspectJAdviceMethod;
    this.aspectJAdvisorFactory = aspectJAdvisorFactory;
    this.aspectInstanceFactory = aspectInstanceFactory;
    this.declarationOrder = declarationOrder;
    this.aspectName = aspectName;

    // 1、延迟初始化
    // 在Spring AOP中,切面类的实例只有一个,比如前面我们一直使用的MyAspect类,
    // 假设我们使用的切面类需要具有某种状态,以适用某些特殊情况的使用,比如多线程环境,此时单例的切面类就不符合我们的要求了。
    // 在Spring AOP中,切面类默认都是单例的,但其还支持另外两种多例的切面实例的切面,即perthis和pertarget,
    // 需要注意的是perthis和pertarget都是使用在切面类的@Aspect注解中的。
    // 这里perthis和pertarget表达式中都是指定一个切面表达式,其语义与前面讲解的this和target非常的相似,
    // perthis表示如果某个类的代理类符合其指定的切面表达式,那么就会为每个符合条件的目标类都声明一个切面实例;
    // pertarget表示如果某个目标类符合其指定的切面表达式,那么就会为每个符合条件的类声明一个切面实例。
    // 从上面的语义可以看出,perthis和pertarget的含义是非常相似的。如下是perthis和pertarget的使用语法:
    // perthis(pointcut-expression)
    // pertarget(pointcut-expression)
    if (aspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
        // Static part of the pointcut is a lazy type.
        Pointcut preInstantiationPointcut = Pointcuts.union(
                aspectInstanceFactory.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,
                aspectInstanceFactory);
        this.lazy = true;
    }
    // 2、立刻初始化
    else {
        // A singleton aspect.
        this.pointcut = this.declaredPointcut;
        this.lazy = false;
        // 初始化增强
        this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut);
    }
}

创建过程中又涉及到perthis和pertarget,无需理会,还是先看单例模式下的创建过程:

/**
 * 根据pointcut初始化增强
 * @param pointcut
 * @return
 */
private Advice instantiateAdvice(AspectJExpressionPointcut pointcut) {
    Advice advice = this.aspectJAdvisorFactory.getAdvice(
            this.aspectJAdviceMethod, pointcut,
            this.aspectInstanceFactory,
            this.declarationOrder,
            this.aspectName);
    return (advice != null ? advice : EMPTY_ADVICE);
}
@Override
@Nullable
public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut,
        MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {

    // 1、获取增强之前的处理
    Class<?> candidateAspectClass = aspectInstanceFactory.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() + "]");
    }


    // 2、针对各种不同的增强,做不同的处理
    AbstractAspectJAdvice springAdvice;
    switch (aspectJAnnotation.getAnnotationType()) {
            // 1、前置增强
        case AtBefore:
            springAdvice = new AspectJMethodBeforeAdvice(candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
            break;
            // 2、后置增强
        case AtAfter:
            springAdvice = new AspectJAfterAdvice(candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
            break;
            // 3、后置返回增强
        case AtAfterReturning:
            springAdvice = new AspectJAfterReturningAdvice(candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
            AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation();
            if (StringUtils.hasText(afterReturningAnnotation.returning())) {
                springAdvice.setReturningName(afterReturningAnnotation.returning());
            }
            break;
            // 4、后置异常增强
        case AtAfterThrowing:
            springAdvice = new AspectJAfterThrowingAdvice(candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
            AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation();
            if (StringUtils.hasText(afterThrowingAnnotation.throwing())) {
                springAdvice.setThrowingName(afterThrowingAnnotation.throwing());
            }
            break;
            // 5、环绕增强
        case AtAround:
            springAdvice = new AspectJAroundAdvice(
                    candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
            break;
            // 6、如果是Pointcut,则不做处理
        case AtPointcut:
            return null;
            // 7、未能满足case条件,抛出异常
        default:
            throw new UnsupportedOperationException("Unsupported advice type on method: " + candidateAdviceMethod);
    }

    // 3、获取增强方法之后,对增强方法进行配置
    springAdvice.setAspectName(aspectName);
    springAdvice.setDeclarationOrder(declarationOrder);
    String[] argNames = this.parameterNameDiscoverer.getParameterNames(candidateAdviceMethod);
    if (argNames != null) {
        springAdvice.setArgumentNamesFromStringArray(argNames);
    }
    springAdvice.calculateArgumentBindings();

    return springAdvice;
}

看到这里,是不是有种豁然开朗的感觉,Spring针对各种不同的增强创建过程,做了不同的处理。创建的过程相对来讲比较简单,感兴趣的同学可以自己debug跟踪看一下,到这里,就完成了增强的创建工作。

5. 从候选增强中查找可用增强

到此已经获得了所有的的增强并将其作为候选增强,接下来从候选增强中找出可以应用到当前指定bean的增强。

/**
 * 从给定的增强中找出可以应用到当前指定bean的增强
 */
protected List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {
    ProxyCreationContext.setCurrentProxiedBeanName(beanName);
    try {
        return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
    }
    finally {
        ProxyCreationContext.setCurrentProxiedBeanName(null);
    }
}

具体的查找方法委托给了AopUtils类的findAdvisorsThatCanApply方法,来看其具体的调用过程:

public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
    // 1、候选增强为空,直接放回
    if (candidateAdvisors.isEmpty()) {
        return candidateAdvisors;
    }
    // 2、处理引介增强
    List<Advisor> eligibleAdvisors = new ArrayList<>();
    for (Advisor candidate : candidateAdvisors) {
        if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
            eligibleAdvisors.add(candidate);
        }
    }
    // 2、处理普通增强
    boolean hasIntroductions = !eligibleAdvisors.isEmpty();
    for (Advisor candidate : candidateAdvisors) {
        // 如果是引介增强则继续循环,因为第一步已经处理过了。
        if (candidate instanceof IntroductionAdvisor) {
            // already processed
            continue;
        }
        if (canApply(candidate, clazz, hasIntroductions)) {
            eligibleAdvisors.add(candidate);
        }
    }
    return eligibleAdvisors;
}

具体的判断过程交给了canApply方法,该方法有多个重载,引介增强和普通增强最后都会调用同一个方法,但是具体的细节处理是不同的,canApply方法的源码:

public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {
    // 1、处理引介增强
    if (advisor instanceof IntroductionAdvisor) {
        return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass);
    }
    // 2、处理普通增强
    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;
    }
}
  1. 引介增强匹配:
    引介增强的处理比较简单,因为引介增强只能应用于接口和类,所以直接使用ClassFilter类的matches方法做匹配即可(ClassFilter已经在前面介绍过了,可以参考29–Pointcut和Advisor以及静态普通方法名匹配切面前面)
  2. 普通增强匹配
public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
    // 1、判断类是否匹配,如类一级别不匹配,直接返回false
    if (!pc.getClassFilter().matches(targetClass)) {
        return false;
    }

    // 2、判断如果当前Advisor所指代的方法的切点表达式如果是对任意方法都放行,直接返回true
    MethodMatcher methodMatcher = pc.getMethodMatcher();
    if (methodMatcher == MethodMatcher.TRUE) {
        // No need to iterate the methods if we're matching any method anyway...
        return true;
    }

    // 3、尝试将methodMatcher转换为IntroductionAwareMethodMatcher,以提高匹配效率
    IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
    if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
        introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
    }

    // 4、获取代理目标的所有接口和实现类
    Set<Class<?>> classes = new LinkedHashSet<>();
    if (!Proxy.isProxyClass(targetClass)) {
        classes.add(ClassUtils.getUserClass(targetClass));
    }
    classes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetClass));

    // 5、循环代理目标的所有接口和实现类的所有方法并调用matches方法做匹配判断
    for (Class<?> clazz : classes) {
        Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
        for (Method method : methods) {
            if (introductionAwareMethodMatcher != null ?
                    // 如果上一步得到的introductionAwareMethodMatcher对象不为空,则使用该对象的matches匹配
                    introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) :
                    // 否则使用Pointcut的methodMatcher对象做匹配
                    methodMatcher.matches(method, targetClass)) {
                return true;
            }
        }
    }
    return false;
}

猜你喜欢

转载自blog.csdn.net/lyc_liyanchao/article/details/83782330
33