Spring源码之创建AOP代理之增强器的获取

前言

在上一篇博文中我们说到了通过自定义配置完成了对 AnnotationAwareAspectJAutoProxyCreator类型的自动注册, 那么这个类究竟做了什么工作从而完成AOP的操作呢?首先我们看一下 AnnotationAwareAspectJAutoProxyCreator的类图结构,如图:

 Spring源码之创建AOP代理之增强器的获取

AOP的源码解析操作入口

从UML类图中我们看到AnnotationAwareAspectJAutoProxyCreator这个类实现了BeanPostProcessor接口,而实现这个BeanPostProcessor后,当Spring加载这个Bean时会在实例化之前调用器postProcessorAfterIntialization方法,而我们就从这里进行分析AOP的逻辑
  • 首先我们先看一下它父类 AbstractAutoProxyCreatorpostProcessorIntialization方法
  • 看源码(具体实现在 AbstractAutoProxyCreator.class)
    /**
     * 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) {
            // 根据bean的class 和 name构建出一个key  格式:beanClassName_beanName
            Object cacheKey = getCacheKey(bean.getClass(), beanName);
            if (this.earlyProxyReferences.remove(cacheKey) != bean) {
                // 如果它适合被代理,则需要指定封装bean
                return wrapIfNecessary(bean, beanName, cacheKey);
            }
        }
        return bean;
}

在上面代码中用到了方法 wrapIfNecessary,进入到该函数方法的内部:

  • 看源码(具体实现在 AbstractAutoProxyCreator.class)
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
        // 如果已经处理过
        if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
            return bean;
        }
        // 无需增强
        if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
            return bean;
        }
        // 给定的bean类是否是一个基础设施类,基础设施类不应该被代理,或者配置了指定的bean不需要代理
        if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
            this.advisedBeans.put(cacheKey, Boolean.FALSE);
            return bean;
        }

        // 如果存在增强方法则创建
        // Create proxy if we have advice.
        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;
        }

        this.advisedBeans.put(cacheKey, Boolean.FALSE);
        return bean;
}
从上面的函数中我们可以大概看出代理的创建过程的一个雏形。当然真正的开始之前还需要一些个判断,比如是否已经处理过或者是 是否需要跳过的bean,而真正创建代理的代码是在getAdvicesAndAdvisorsForBean函数开始的。

创建代理需要两个步骤:

  1. 获取增强方法或增强器;
  2. 根据获取的增强来进行代理。

上述两个步骤其中逻辑是十分复杂的,首先来看看获取增强方法的逻辑实现。获取增强的方法 getAdvicesAndAdvisorsForBean是在 AbstractAdvisorAuroProxyCreator中实现的,代码如下:

  • 看源码(具体实现在 AbstractAdvisorAuroProxyCreator.class)
@Override
@Nullable
protected Object[] getAdvicesAndAdvisorsForBean(
            Class beanClass, String beanName, @Nullable TargetSource targetSource) {

        List advisors = findEligibleAdvisors(beanClass, beanName);
        if (advisors.isEmpty()) {
            return DO_NOT_PROXY;
        }
        return advisors.toArray();
}
  • 源码分析

主要查看上述函数体内的 findEligibleAdvisor方法。进入该方法实现也在 AbstractAdvisorAuroProxyCreator.class

  • 看源码(具体实现在 AbstractAdvisorAutoProxyCreator.class)
protected List findEligibleAdvisors(Class beanClass, String beanName) {
        List candidateAdvisors = findCandidateAdvisors();
        List eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
        extendAdvisors(eligibleAdvisors);
        if (!eligibleAdvisors.isEmpty()) {
            eligibleAdvisors = sortAdvisors(eligibleAdvisors);
        }
        return eligibleAdvisors;
}
  • 源码分析

通过 findEligbleAdvisor的具体实现我们看到,对于指定bean的增强方法的获取包含了两个步骤:

  1. 获取所有增强,
  2. 寻找所有增强中 对于bean的增强并应用(也就是寻找匹配bean的增强器)。

函数中的 findCandidateAdvisorsfindAdvisorsThatCanApply便是做了这两件事

当然如果这个方法没有找到增强器, getAdvicesAndAdvisorsForBean就会返回一个 DO_NOT_PROXY, DO_NOT_PROXY时已经定义好的 null

获取增强器

从一开始我们分析的就是基于注解进行的AOP,所以对于 findidateAdvisors的实现是由 AnnotationAwareAspectJAutoProxyCreator类的 findCandidateAdvisors方法完成的。

  • 看源码(具体实现在 AnnotationAwareAspectJAutoProxyCreator.class)
@Override
protected List findCandidateAdvisors() {
        // Add all the Spring advisors found according to superclass rules.
        // 当使用注解方式配置AOP的时候并不是对xml配置文件的支持进行了丢弃
        // 在这里调用父类加载配置文件中的AOP声明
        List advisors = super.findCandidateAdvisors();
        // Build Advisors for all AspectJ aspects in the bean factory.
        if (this.aspectJAdvisorsBuilder != null) {
            advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
        }
        return advisors;
}
  • 源码解析:

首先我们先看一下 AnnotationAwareAspectJAutoProxyCreator.class这个类的UML,

 Spring源码之创建AOP代理之增强器的获取

在上图中我们看到 AnnotationAwareAspectJAutoProxyCreator间接继承了 AbstractAdvisorsAutoProxyCreator,在实现获取增强方法中保留了父类的获取配置文件中定义的增强,是由 List<advisor> advisors = super.findCandidateAdvisors();</advisor>实现;

此外同时还添加了获取Bean的注解增强的功能,是由 this.aspectJAdvisorsBuilder.buildAspectJAdvisors()这个方法实现的

Spring获取增强器(增强方法)的解析思路大致如下:

  1. 获取所有的beanName,这一步骤中所有的beanFactory中注册的Bean都会被提取出来。
  2. 遍历所有的beanName,并找出使用**@Aspect注解声明的类,并进行进一步处理。
  3. 对于标记Aspect注解的类进行增强器的提取。
  4. 将提取结果加入缓存

接下来我们分析一下以上步骤的实现,首先

  • this.aspectJAdvisorsBuilder.buildAspectJAdvisors()源码的实现(具体实现在 BeanFactoryAspectJAdvisorsBuilder.class)
public List buildAspectJAdvisors() {
        List aspectNames = this.aspectBeanNames;

        if (aspectNames == null) {
            synchronized (this) {
                aspectNames = this.aspectBeanNames;
                if (aspectNames == null) {
                    List advisors = new ArrayList<>();
                    aspectNames = new ArrayList<>();
                    // 获取所有的beanName
                    String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
                            this.beanFactory, Object.class, true, false);
                    // 循环所有的beanName获取 获取声明AspectJ的类,找出对应的增强方法
                    for (String beanName : beanNames) {
                        // 不合法的bean 则略过,由子类定义规则返回true
                        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类型
                        Class beanType = this.beanFactory.getType(beanName, false);
                        if (beanType == null) {
                            continue;
                        }
                        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 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 advisors = new ArrayList<>();
        for (String aspectName : aspectNames) {
            List 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;
}
&#x6267;&#x884C;&#x5230;&#x6B64;&#xFF0C;Spring&#x5C31;&#x5B8C;&#x6210;&#x4E86;Advisor&#x7684;&#x63D0;&#x53D6;&#xFF0C;&#x5728;&#x4E0A;&#x9762;&#x7684;&#x6B65;&#x9AA4;&#x4E2D;**&#x6700;&#x7E41;&#x6742;&#x6700;&#x91CD;&#x8981;**&#x7684;&#x5C31;&#x662F;&#x589E;&#x5F3A;**&#x5668;&#x7684;&#x83B7;&#x53D6;**&#xFF0C;&#x800C;&#x8FD9;&#x4E00;&#x6B65;&#x53C8;&#x4EA4;&#x7ED9;&#x4E86;getAdvisors&#x65B9;&#x6CD5;&#x53BB;&#x5B9E;&#x73B0;&#x7684;&#x3002;(this.advisorFactory.getAdvisors(factory);)
  • 首先看 this.advisorFactory.isAspect(beanType)源码(具体实现在 AbstractAspectJAdvisorFactory.class)
@Override
public boolean isAspect(Class clazz) {
        return (hasAspectAnnotation(clazz) && !compiledByAjc(clazz));
    }

private boolean hasAspectAnnotation(Class clazz) {
        return (AnnotationUtils.findAnnotation(clazz, Aspect.class) != null);
}

紧接着再查看一下 findAnnotation方法:

@Nullable
public static  A findAnnotation(Class clazz, @Nullable Class annotationType) {
        if (annotationType == null) {
            return null;
        }

        // Shortcut: directly present on the element, with no merging needed?
        if (AnnotationFilter.PLAIN.matches(annotationType) ||
                AnnotationsScanner.hasPlainJavaAnnotationsOnly(clazz)) {
            // 判断此Class 是否存在Aspect.class注解
            A annotation = clazz.getDeclaredAnnotation(annotationType);
            if (annotation != null) {
                return annotation;
            }
            // For backwards compatibility, perform a superclass search with plain annotations
            // even if not marked as @Inherited: e.g. a findAnnotation search for @Deprecated
            Class superclass = clazz.getSuperclass();
            if (superclass == null || superclass == Object.class) {
                return null;
            }
            return findAnnotation(superclass, annotationType);
        }

        // Exhaustive retrieval of merged annotations...
        return MergedAnnotations.from(clazz, SearchStrategy.TYPE_HIERARCHY, RepeatableContainers.none())
                .get(annotationType).withNonMergedAttributes()
                .synthesize(MergedAnnotation::isPresent).orElse(null);
}

这里如果bean存在 Aspect.class注解,那么就可以获取此bean的增强器了,接下来我们回到 BeanFactoryAspectJAdvisorsBuilder类中查看 this.advisorFactory.getAdvisors(factory);方法。

  • 看源码(具体实现在 ReflectiveAspectJAdvisorFactory.class)
@Override
public List getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
        // 获取标记AspectJ的类
        Class aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
        // 获取标记AspectJ的name
        String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();
        validate(aspectClass);

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

        List advisors = new ArrayList<>();
        // 对于aspect class的每一个带有注解的方法进行循环(除了@Pointcut注解的方法除外),取得Advisor,并添加到集合里
        // 这里应该取到的是Advice,然后取得我们自定义的切面类中的PointCut,组合成Advisor
        for (Method method : getAdvisorMethods(aspectClass)) {
            // Prior to Spring Framework 5.2.7, advisors.size() was supplied as the declarationOrderInAspect
            // to getAdvisor(...) to represent the "current position" in the declared methods list.
            // However, since Java 7 the "current position" is not valid since the JDK no longer
            // returns declared methods in the order in which they are declared in the source code.
            // Thus, we now hard code the declarationOrderInAspect to 0 for all advice methods
            // discovered via reflection in order to support reliable advice ordering across JVM launches.
            // Specifically, a value of 0 aligns with the default value used in
            // AspectJPrecedenceComparator.getAspectDeclarationOrder(Advisor).
            // 将类中的方法封装成Advisor
            Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, 0, 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;
}
普通增强器的获取

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

首先我们看一下 getAdvisorMethods(aspectClass)这个方法,它很巧妙的使用接口定义一个匿名回调,把带有注解的Method都取出来,放到集合里。

  • 看源码
private List getAdvisorMethods(Class aspectClass) {
        List methods = new ArrayList<>();
        ReflectionUtils.doWithMethods(aspectClass, methods::add, adviceMethodFilter);
        if (methods.size() > 1) {
            methods.sort(adviceMethodComparator);
        }
        return methods;
}

然后在看一下函数体内的 doWithMethods方法 具体实现在 ReflectionUtils

public static void doWithMethods(Class clazz, MethodCallback mc, @Nullable MethodFilter mf) {
        // Keep backing up the inheritance hierarchy.
        Method[] methods = getDeclaredMethods(clazz, false);
        for (Method method : methods) {
            if (mf != null && !mf.matches(method)) {
                continue;
            }
            try {
                mc.doWith(method);
            }
            catch (IllegalAccessException ex) {
                throw new IllegalStateException("Not allowed to access method '" + method.getName() + "': " + ex);
            }
        }
        if (clazz.getSuperclass() != null && (mf != USER_DECLARED_METHODS || clazz.getSuperclass() != Object.class)) {
            doWithMethods(clazz.getSuperclass(), mc, mf);
        }
        else if (clazz.isInterface()) {
            for (Class superIfc : clazz.getInterfaces()) {
                doWithMethods(superIfc, mc, mf);
            }
        }
}

然后我们在回到 ReflectiveAspectJAdvisorFactory.class类中获取普通增强器的 getAdvisor方法

  • 看源码(具体实现在 ReflectiveAspectJAdvisorFactory.class)
@Override
@Nullable
public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
            int declarationOrderInAspect, String aspectName) {

        validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());

        // 获取Pointcut信息 主要是获取Pointcut表达式
        // 把Method对象也传进去的目的是,比较Method对象上的注解,是不是下面的注解的其中的一个,
        // 如果不是返回null;如果是就把Pointcut内容包装返回
        AspectJExpressionPointcut expressionPointcut = getPointcut(
                candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
        if (expressionPointcut == null) {
            return null;
        }

        // 根据Pointcut信息生成增强器
        return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
                this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
}
切点信息的获取

所谓获取切点信息就是指注解的表达式信息的获取,如@Before(“test()”)。

  • 看源码(具体在 ReflectiveAspectJAdvisorFactory.class)
@Nullable
private AspectJExpressionPointcut getPointcut(Method candidateAdviceMethod, Class candidateAspectClass) {
        // 获取方法上的注解,比较Method对象上的注解是不是下面其中的一个,如果不是返回null
        // 被比较的注解:Pointcut.class, Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class
        AspectJAnnotation aspectJAnnotation =
                AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
        if (aspectJAnnotation == null) {
            return null;
        }

        // 使用AspectJExpressionPointcut实例封装获取的信息
        AspectJExpressionPointcut ajexp =
                new AspectJExpressionPointcut(candidateAspectClass, new String[0], new Class[0]);
        // 提取到注解中的表达式并设置进去
        ajexp.setExpression(aspectJAnnotation.getPointcutExpression());
        if (this.beanFactory != null) {
            ajexp.setBeanFactory(this.beanFactory);
        }
        return ajexp;
}

我们再看一下上面使用到的 findAspectJAnnotationOnMethod方法的实现

  • 看源码(具体是现在 AbstractAspectJAdvisorFactory.class)
@Nullable
protected static AspectJAnnotation findAspectJAnnotationOnMethod(Method method) {
        for (Class clazz : ASPECTJ_ANNOTATION_CLASSES) {
            AspectJAnnotation foundAnnotation = findAnnotation(method, (Class) clazz);
            if (foundAnnotation != null) {
                return foundAnnotation;
            }
        }
        return null;
}

小插曲:注意一下上面的 ASPECTJ_ANNOTATION_CLASSES变量,它设置了查找的注解类:

  • 源码
private static final Class[] ASPECTJ_ANNOTATION_CLASSES = new Class[] {
            Pointcut.class, Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class};

再次回到 findAspectJAnnotationOnMethod方法的实现,里面使用了 findAnnotation方法,跟踪该方法

  • 看源码(具体实现在 AbstractAspectAdvisorFacrory.class)
    /**
     * 获取指定方法上的注解 并使用AspectAnnotation进行封装
     * @param method
     * @param toLookFor
     * @param
     * @return
     */
@Nullable
private static  AspectJAnnotation findAnnotation(Method method, Class toLookFor) {
        A result = AnnotationUtils.findAnnotation(method, toLookFor);
        if (result != null) {
            return new AspectJAnnotation<>(result);
        }
        else {
            return null;
        }
}

此方法的功能是获取指定方法上的注解并使用 AspectJAnnotation封装。

根据切点信息获取增强类

所有的增强都由 Advisor实现类 InstantiationModelAwarePointCutAdvisorImpl进行统一封装。我们简单看一下其构造函数:

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;

        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;
        }
        else {
            // A singleton aspect.
            this.pointcut = this.declaredPointcut;
            this.lazy = false;
            // 初始化Advice
            this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut);
        }
}
&#x901A;&#x8FC7;&#x5BF9;&#x4E0A;&#x9762;&#x7684;&#x6784;&#x9020;&#x51FD;&#x6570;&#x7684;&#x5206;&#x6790;&#xFF0C;&#x53D1;&#x73B0;&#x5C01;&#x88C5;&#x8FC7;&#x7A0B;&#x53EA;&#x662F;&#x7B80;&#x5355;&#x7684;&#x5C06;&#x4FE1;&#x606F;&#x5C01;&#x88C5;&#x5728;&#x7C7B;&#x7684;&#x5B9E;&#x4F8B;&#x4E2D;&#xFF0C;&#x6240;&#x6709;&#x7684;&#x4FE1;&#x606F;&#x90FD;&#x662F;&#x5355;&#x7EAF;&#x7684;&#x590D;&#x5236;&#x3002;&#x5728;&#x5B9E;&#x4F8B;&#x521D;&#x59CB;&#x5316;&#x7684;&#x5DE5;&#x7A0B;&#x4E2D;&#x8FD8;&#x5B8C;&#x6210;&#x4E86;&#x5BF9;&#x4E8E;&#x589E;&#x5F3A;&#x5668;&#x7684;&#x521D;&#x59CB;&#x5316;&#x3002;&#x56E0;&#x4E3A;&#x4E0D;&#x540C;&#x7684;&#x589E;&#x5F3A;&#x6240;&#x4F53;&#x73B0;&#x7684;&#x903B;&#x8F91;&#x662F;&#x4E0D;&#x540C;&#x7684;&#xFF0C;&#x6BD4;&#x5982;@Before("test()")&#x548C;@After("test()")&#x6807;&#x7B7E;&#x7684;&#x4E0D;&#x540C;&#x5C31;&#x662F;&#x589E;&#x5F3A;&#x5668;&#x7684;&#x4F4D;&#x7F6E;&#x4E0D;&#x540C;&#xFF0C;&#x6240;&#x4EE5;&#x9700;&#x8981;&#x4E0D;&#x540C;&#x7684;&#x589E;&#x5F3A;&#x5668;&#x6765;&#x5B8C;&#x6210;&#x4E0D;&#x540C;&#x7684;&#x903B;&#x8F91;&#xFF0C;&#x800C;&#x6839;&#x636E;&#x6CE8;&#x89E3;&#x4E2D;&#x7684;&#x4FE1;&#x606F;&#x521D;&#x59CB;&#x5316;&#x5BF9;&#x5E94;&#x7684;&#x589E;&#x5F3A;&#x5668;&#x5C31;&#x662F;&#x5728;instantiateAdvice&#x51FD;&#x6570;&#x4E2D;&#x5B9E;&#x73B0;&#x7684;&#xFF0C;&#x7EE7;&#x7EED;&#x8DDF;&#x8E2A;&#x6E90;&#x7801;&#xFF1A;
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);
}
&#x63A5;&#x4E0B;&#x6765;&#x518D;&#x7EE7;&#x7EED;&#x8DDF;&#x8E2A;getAdvice&#x51FD;&#x6570;&#x7684;&#x5177;&#x4F53;&#x5B9E;&#x73B0;
  • 看源码(具体实现在 ReflectiveAspectJAdvisorFactory.class)
@Override
@Nullable
public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut,
            MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {

        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() + "]");
        }

        if (logger.isDebugEnabled()) {
            logger.debug("Found AspectJ method: " + candidateAdviceMethod);
        }

        AbstractAspectJAdvice springAdvice;

        // 根据不同的注解类型封装不同的增强器
        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())) {
                    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);
        }

        // Now to configure the advice...
        springAdvice.setAspectName(aspectName);
        springAdvice.setDeclarationOrder(declarationOrder);
        String[] argNames = this.parameterNameDiscoverer.getParameterNames(candidateAdviceMethod);
        if (argNames != null) {
            springAdvice.setArgumentNamesFromStringArray(argNames);
        }
        springAdvice.calculateArgumentBindings();

        return springAdvice;
}
前置增强

从上面的函数中我们看到,Spring会根据不同的注解生成不同的增强器,具体表现在了 switch (aspectJAnnotation.getAnnotationType()),根据不同的类型来生成。例如在 AtBefore会对应 AspectJMethodBeforeAdvice,早AspectJMethodBeforeAdvice中完成了增强逻辑,

&#x5E76;&#x4E14;&#x8FD9;&#x91CC;&#x7684;**AspectJMethodBeforeAdvice**&#x6700;&#x540E;&#x88AB;&#x9002;&#x914D;&#x5668;&#x5C01;&#x88C5;&#x6210;**MethodBeforeAdviceInterceptor**,

如何被封装的 这有机再在分析。

我们先看一下 MethodBeforeAdviceInterceptor的代码

  • 看源码
public class MethodBeforeAdviceInterceptor implements MethodInterceptor, BeforeAdvice, Serializable {

    private final MethodBeforeAdvice advice;

    /**
     * Create a new MethodBeforeAdviceInterceptor for the given advice.
     * @param advice the MethodBeforeAdvice to wrap
     */
    public MethodBeforeAdviceInterceptor(MethodBeforeAdvice advice) {
        Assert.notNull(advice, "Advice must not be null");
        this.advice = advice;
    }

    @Override
    @Nullable
    public Object invoke(MethodInvocation mi) throws Throwable {
        this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
        return mi.proceed();
    }

}

其中上述代码的 MethodBeforeAdvice代表的前置增强的 AspectJMethodBeforeAdvice,根据 before方法来到这个类。

  • 看源码(具体实现在 AspectJMethodBeforeAdvice.java)
@Override
public void before(Method method, Object[] args, @Nullable Object target) throws Throwable {
        // 直接调用增强方法
        invokeAdviceMethod(getJoinPointMatch(), null, null);
}

继续跟踪函数体内的 invokeAdviceMethod方法

  • 看源码(具体实现在 AbstractAspectJAdvice.java)
protected Object invokeAdviceMethod(
            @Nullable JoinPointMatch jpMatch, @Nullable Object returnValue, @Nullable Throwable ex)
            throws Throwable {

        return invokeAdviceMethodWithGivenArgs(argBinding(getJoinPoint(), jpMatch, returnValue, ex));
}

接着继续根据函数体内的 invokeAdviceMethodWithGivenArgs方法,

  • 看源码(具体实现在 AbstractAspectJAdvice.java)
protected Object invokeAdviceMethodWithGivenArgs(Object[] args) throws Throwable {
        Object[] actualArgs = args;
        if (this.aspectJAdviceMethod.getParameterCount() == 0) {
            actualArgs = null;
        }
        try {
            ReflectionUtils.makeAccessible(this.aspectJAdviceMethod);
            // 通过反射调用AspectJ注解类中的增强方法
            return this.aspectJAdviceMethod.invoke(this.aspectInstanceFactory.getAspectInstance(), actualArgs);
        }
        catch (IllegalArgumentException ex) {
            throw new AopInvocationException("Mismatch on arguments to advice method [" +
                    this.aspectJAdviceMethod + "]; pointcut expression [" +
                    this.pointcut.getPointcutExpression() + "]", ex);
        }
        catch (InvocationTargetException ex) {
            throw ex.getTargetException();
        }
}

invokeAdviceMethodWithGivenArgs方法中的aspectJAdviceMethod正是对前置增强的方法,在这里实现了调用。

简单总结

前置通知的大致过程是在拦截器链中放置 MethodBeforeAdviceInterceptor,而在 MethodBeforeAdvivceInterceptor中又放置了 AspectJMethodBeforeAdvice,并在调用invoke时首先串联调用。

后置增强

相比前置增强略有不同,后置增强没有提供中间的类,而是直接在拦截器中使用过了中间的 AspectJAfterAdvice,也就是直接实现了 MethodInterceptor

  • 看源码(AspectJAfterAdvice.java)
public class AspectJAfterAdvice extends AbstractAspectJAdvice
        implements MethodInterceptor, AfterAdvice, Serializable {

    public AspectJAfterAdvice(
            Method aspectJBeforeAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aif) {

        super(aspectJBeforeAdviceMethod, pointcut, aif);
    }

    @Override
    @Nullable
    public Object invoke(MethodInvocation mi) throws Throwable {
        try {
            return mi.proceed();
        }
        finally {
            // 激活增强方法
            invokeAdviceMethod(getJoinPointMatch(), null, null);
        }
    }

    @Override
    public boolean isBeforeAdvice() {
        return false;
    }

    @Override
    public boolean isAfterAdvice() {
        return true;
    }

}

其他的几个增强器,下次具体来看

寻找匹配的增强器
&#x524D;&#x9762;&#x7684;&#x51FD;&#x6570;&#x4E2D;&#x5DF2;&#x7ECF;&#x5B8C;&#x6210;&#x4E86;&#x6240;&#x6709;&#x589E;&#x5F3A;&#x5668;&#x7684;&#x89E3;&#x6790;&#xFF0C;&#x4E5F;&#x5C31;&#x662F;&#x8BB2;&#x89E3;&#x5B8C;&#x4E86;&#x5173;&#x4E8E;findCandidateAdvisors&#x65B9;&#x6CD5;&#xFF1B;&#x4F46;&#x662F;&#x5BF9;&#x4E8E;&#x6240;&#x6709;&#x589E;&#x5F3A;&#x5668;&#x6765;&#x8BB2;&#xFF0C;&#x5E76;&#x4E0D;&#x4E00;&#x5B9A;&#x90FD;&#x9002;&#x7528;&#x4E8E;&#x5F53;&#x524D;&#x7684;bean&#xFF0C;&#x8FD8;&#x8981;&#x53D6;&#x51FA;&#x9002;&#x5408;&#x7684;&#x589E;&#x5F3A;&#x5668;&#xFF0C;&#x4E5F;&#x5C31;&#x662F;&#x6EE1;&#x8DB3;&#x6211;&#x4EEC;&#x914D;&#x7F6E;&#x7684;&#x901A;&#x914D;&#x7B26;&#x7684;&#x589E;&#x5F3A;&#x5668;&#xFF0C;&#x5177;&#x4F53;&#x5B9E;&#x73B0;&#x5728;findAdvisorsThatCanAply&#x4E2D;&#xFF0C;&#x6211;&#x4EEC;&#x9700;&#x8981;&#x56DE;&#x5230;&#x6700;&#x521D;&#x7684;**AbstractAdvisorAuroProxyCreator**&#x7C7B;&#x4E2D;&#xFF0C;&#x7136;&#x540E;&#x8FDB;&#x5165;&#x5230;findEligibleAdvisors&#x51FD;&#x6570;&#x5185;&#x7684;**findAdvisorsThatCanAply**&#x65B9;&#x6CD5;&#x7684;&#x5B9E;&#x73B0;&#xFF1A;
  • 看源码(AbstractAdvisorAuroProxyCreator.java)
protected List findAdvisorsThatCanApply(
            List 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 findAdvisorsThatCanApply(List candidateAdvisors, Class clazz) {
        if (candidateAdvisors.isEmpty()) {
            return candidateAdvisors;
        }
        List eligibleAdvisors = new ArrayList<>();
        // 首先处理引介增强
        /*
         * 引介增强是一种特殊的增强,其它的增强是方法级别的增强,即只能在方法前或方法后添加增强。
         * 而引介增强则不是添加到方法上的增强, 而是添加到类方法级别的增强,即可以为目标类动态实现某个接口,
         * 或者动态添加某些方法。我们通过下面的事例演示引介增强的使用
         */
        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) {
                // already processed
                continue;
            }
            // 对于普通bean的 进行处理
            if (canApply(candidate, clazz, hasIntroductions)) {
                eligibleAdvisors.add(candidate);
            }
        }
        return eligibleAdvisors;
}

findAdvisorsThatCanApply函数的主要功能时寻找增强器中适用于当前class的增强器。 引介增强普通增强的处理是不一样的,所以分开处理。而对于真正的匹配在 canApply中实现。

接着跟踪 canApply方法

  • 看源码(AopUtils.java)
public static boolean canApply(Pointcut pc, Class targetClass, boolean hasIntroductions) {
        Assert.notNull(pc, "Pointcut must not be null");
        // 通过Pointcut的条件判断此类是否匹配
        if (!pc.getClassFilter().matches(targetClass)) {
            return false;
        }

        MethodMatcher methodMatcher = pc.getMethodMatcher();
        if (methodMatcher == MethodMatcher.TRUE) {
            // No need to iterate the methods if we're matching any method anyway...
            return true;
        }

        IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
        if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
            introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
        }

        Set> classes = new LinkedHashSet<>();
        if (!Proxy.isProxyClass(targetClass)) {
            classes.add(ClassUtils.getUserClass(targetClass));
        }
        classes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetClass));

        for (Class clazz : classes) {
            // 反射获取类中所有的方法
            Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
            for (Method method : methods) {
                // 根据匹配原则判断该方法是否能匹配Pointcut中的规则,如果有一个方法匹配则返回true
                if (introductionAwareMethodMatcher != null ?
                        introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) :
                        methodMatcher.matches(method, targetClass)) {
                    return true;
                }
            }
        }

        return false;
}
  • 源码分析

首先会判断bean是否满足切点的规则,如果能满足,则获取bean的所有方法,判断是否有方法能够匹配规则,有方法匹配规则就代表 Advisor能作用于该bean,该方法就会返回true,然后 findAdvisorsThatCanApply函数就会将Advisor加入到 eligibleAdvisors中。

最后我们以注解的规则来看一下bean的method是怎样匹配Pointcut中的规则的
  • 看源码(AnnotationMethodMatcher.java)
@Override
public boolean matches(Method method, Class targetClass) {
        if (matchesMethod(method)) {
            return true;
        }
        // Proxy classes never have annotations on their redeclared methods.
        if (Proxy.isProxyClass(targetClass)) {
            return false;
        }
        // The method may be on an interface, so let's check on the target class as well.
        Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass);
        return (specificMethod != method && matchesMethod(specificMethod));
    }

    private boolean matchesMethod(Method method) {
        // 可以看出判断该Advisor是否使用于bean中的method,只需看method上是否有Advisor的注解
        return (this.checkInherited ? AnnotatedElementUtils.hasAnnotation(method, this.annotationType) :
                method.isAnnotationPresent(this.annotationType));
}

至此:在后置处理器中找到了所有匹配Bean中的增强器,

Original: https://www.cnblogs.com/java-wang/p/15375678.html
Author: 码上遇见你
Title: Spring源码之创建AOP代理之增强器的获取

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/580134/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • 奇怪的知识又增加了,ImageMagick PDF转JPG图片合并的时候报Unsupported Image Type

    之前在PDF转JPG时使用了ImageMagic这个强大的工具,起初使用都没有什么问题,但是突然生产出现部分转换后的图片合并失败的问题 报错信息: javax.imageio.II…

    Java 2023年6月7日
    095
  • docker打包Python项目成镜像文件

    做实验时因为数据太大用到了学校的服务器平台,在平台进行训练的时候首先需要搭建环境,由于种种原因,只能自己用docker来打包镜像文件,自己做镜像。记录一下遇到的坑以及解决方法。 d…

    Java 2023年6月5日
    0102
  • 面向对象设计六大原则

    六大设计原则主要是指: 单一职责原则(Single Responsibility Principle); 开闭原则(Open Closed Principle); 里氏替换原则(L…

    Java 2023年6月9日
    085
  • Spring Boot入门篇,动力节点学习笔记

    多年来,随着新功能的增加,spring变得越来越复杂。只需访问https://spring.io/projects页面,我们就会看到可以在我们的应用程序中使用的所有Spring项目…

    Java 2023年6月7日
    075
  • 接口和抽象类的区别(不讲废话,干货满满,JDK1.8最新整理)

    接口和抽象类的区别(不讲废话,干货满满,JDK1.8最新整理) 1、抽象类 以下说辞可能不太准确,但是会让你醍醐灌顶 抽象类是把一些具有共同属性(包括行为)的东西抽象出来,比如: …

    Java 2023年6月9日
    0148
  • Google支付和服务端验证

    因为公司业务需求,需要使用google的登录和支付。google支付分为订阅和应用内购买两种,笔者使用的是应用内购买这种方式,这里将整个google支付和支付验证的流程记录下来。 …

    Java 2023年5月30日
    088
  • 动态代理

    动态代理。 讲到动态代理,就有对应的静态代理 静态代理的实现,方式1 继承目标类,生成一个子类。代理类和目标类是父子的关系。 然后在子类中进行逻辑的扩展,完成了静态代理。 方式2 …

    Java 2023年6月5日
    092
  • Java 注解

    Java的注解是个很神奇的东西,它既可以帮你生成代码,又可以结合反射来在运行时获得注解标识的对象,进行逻辑处理,它能帮助我们完成很多很多不可能完成的任务,这回我们就来一起来了解下它…

    Java 2023年5月29日
    099
  • maven bug解决

    [ERROR] Failed to execute goal on project cloud-consumer-feign-order80: Could not resolve …

    Java 2023年6月15日
    0131
  • 普通module如何使用@Test测试

    问题 对于一个 maven工程来说,使用@Test注解来测试只需要在 pom.xml中引入test的依赖即可。但是对于一个普通的 module那又怎么使用呢? 最方便的就是 alt…

    Java 2023年6月7日
    0107
  • hdfs常用shell命令

    1、创建文件夹 hadoop fs -mkdir [-p] … path 为待创建的目录 -p选项的行为与Unix mkdir -p非常相似,它会沿着路径创建父目录。 …

    Java 2023年6月5日
    086
  • Java SE 枚举,注解,增强for循环

    Java SE 进阶 1.Enum 枚举对象名通常使用全部大写,常量的命名规范 构造器私有化 本类内部创建一组对象 对外暴露对象(通过为对象添加 public final stat…

    Java 2023年6月7日
    082
  • Spring Cloud Sleuth+ZipKin+ELK服务链路追踪(七)

    序言 sleuth是spring cloud的分布式跟踪工具,主要记录链路调用数据,本身只支持内存存储,在业务量大的场景下,为拉提升系统性能也可通过http传输数据,也可换做rab…

    Java 2023年5月30日
    086
  • python爬虫配置IP代理池(ProxyPool)

    关注我的公众号【靠谱杨的挨踢生活】回复 ProxyPool可以免费获取网盘链接。也可自行搜索下载:https://github.com/Python3WebSpider/Proxy…

    Java 2023年6月15日
    097
  • 在VS2013下配置BOOST库

    1、安装Boost库 (1)、首先打开Boost的官网(http://www.boost.org/),找到下载位置,如下图中红框所示,此时最新的版本是1.64.0: (2)、点击进…

    Java 2023年6月5日
    083
  • 单链表(Java–尚硅谷)

    大体结构和C++的链表差不多 补充之前不知道的:链表分两类,带和不带头结点的链表 现在才知道,Java没有像C/C++那样的指针 首先创建一个 LinkList类,然后把链表的各个…

    Java 2023年6月7日
    070
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球