Spring基于注解形式的 AOP的原理流程及源码解析(二)

在阅读此博客的同时打开源码,边看博客边看源码,博客上对源码的关键位置做了注释,能很大程度上降低源码的阅读难度。

概括 : 切面Advisor由切入点pointcut及通知advice组成,切入点指明被代理的对象,通知指明被织入的方法,pointcut一般在注解上定义,通知一般就是注解标识的方法

AnnotationAwareAspectJAutoProxyCreator的类层级结构图:

《Spring基于注解形式的 AOP的原理流程及源码解析(二)》

AnnotationAwareAspectJAutoProxyCreator间接实现了SmartInstantiationAwareBeanPostProcessor,因此其算是一个Bean的后处理器,在实例化每个Bean的时候都会调用其父类相应的方法,此类通过重写父类的方法对每个Bean的实例化流程加入AOP的逻辑。

BeanPostProcessor对Bean的实例化过程中执行的第一个方法是:postProcessBeforeInstantiation(),
在每一个Bean实例化之前就调用,如果返回的不是null,则就不会再创建Bean,直接使用此方法的返回值作为Bean实例。AnnotationAwareAspectJAutoProxyCreator最开始执行postProcessBeforeInstantiation方法,此方法在其父类AbstractAutoProxyCreator中:
代码块1

public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware {

    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
        Object cacheKey = getCacheKey(beanClass, beanName);

        if (beanName == null || !this.targetSourcedBeans.contains(beanName)) {
            if (this.advisedBeans.containsKey(cacheKey)) {
                return null;
            }
            //重点关注shouldSkip这个方法,shouldSkip一般返回的都是false,但是执行了很多其他的步骤
            if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
                this.advisedBeans.put(cacheKey, Boolean.FALSE);
                return null;
            }
        }
        //此步一般不会触发,除非我们自定义了customTargetSourceCreators属性
        // 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.
        if (beanName != null) {
            TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
            if (targetSource != null) {
                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;
    }
}

AspectJAwareAdvisorAutoProxyCreator对shouldSkip方法做了重载:
代码块2

public class AspectJAwareAdvisorAutoProxyCreator extends AbstractAdvisorAutoProxyCreator {

protected boolean shouldSkip(Class<?> beanClass, String beanName) {
    // TODO: Consider optimization by caching the list of the aspect names
    //在这一步对Spring容器内所有的BeanDefinition的标识了@Aspect的类的相应切面信息解析缓存起来
    List<Advisor> candidateAdvisors = findCandidateAdvisors();
    for (Advisor advisor : candidateAdvisors) {
        if (advisor instanceof AspectJPointcutAdvisor) {
            //实际返回的类型均不会是AspectJPointcutAdvisor,因此不会直接返回true
            if (((AbstractAspectJAdvice) advisor.getAdvice()).getAspectName().equals(beanName)) {
                return true;
            }
        }
    }
    return super.shouldSkip(beanClass, beanName);
    }

    //AnnotationAwareAspectJAutoProxyCreator对此方法做了重载,先执行此方法,然后执行其自定义的流程
    protected List<Advisor> findCandidateAdvisors() {
        //获取Spring容器内所有的实现了Advisor的Bean
        return this.advisorRetrievalHelper.findAdvisorBeans();
    }

}

AnnotationAwareAspectJAutoProxyCreator重载findCandidateAdvisors方法,从方法字面理解就是获取所有合适的Advisor,AOP切面:
代码块3

public class AnnotationAwareAspectJAutoProxyCreator extends AspectJAwareAdvisorAutoProxyCreator {

    protected List<Advisor> findCandidateAdvisors() {
        // Add all the Spring advisors found according to superclass rules.
        List<Advisor> advisors = super.findCandidateAdvisors();
        // Build Advisors for all AspectJ aspects in the bean factory.
        //重点是buildAspectJAdvisors这个方法
                advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
        return advisors;
    }
}

AnnotationAwareAspectJAutoProxyCreator在initBeanFactory方法内对aspectJAdvisorsBuilder属性初始化为BeanFactoryAspectJAdvisorsBuilderAdapter类型的对象,接下来看其buildAspectJAdvisors方法:
代码块4

public class BeanFactoryAspectJAdvisorsBuilder {

    private volatile List<String> aspectBeanNames;

    private final Map<String, List<Advisor>> advisorsCache = new ConcurrentHashMap<String, List<Advisor>>();

    private final Map<String, MetadataAwareAspectInstanceFactory> aspectFactoryCache =
            new ConcurrentHashMap<String, MetadataAwareAspectInstanceFactory>();

    /** * 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;
        //在Spring容器的BeanPostProcessor实例化之后,初始化第一个普通Bean时,还未对容器内的普通的BeanDefinitions解析
        //在触发实例化第一个Bean时解析所有的BeanDefinition,获取所有的切面类名,仅解析一次
        if (aspectNames == null) {
            synchronized (this) {
                aspectNames = this.aspectBeanNames;
                if (aspectNames == null) {
                    List<Advisor> advisors = new LinkedList<Advisor>();
                    aspectNames = new LinkedList<String>();
                    //获取所有Bean名称,普通的Bean均未实例化
                    String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
                            this.beanFactory, Object.class, true, false);
                    for (String beanName : beanNames) {
                        //判断是否符合条件,BeanFactoryAspectJAdvisorsBuilderAdapter对此方法做了重载
                        //如果AnnotationAwareAspectJAutoProxyCreator未指定includePatterns时均合格。
                        //可以指定includePatterns,设置包名及类路径等对被代理类做筛选
                        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.
                        Class<?> beanType = this.beanFactory.getType(beanName);
                        if (beanType == null) {
                            continue;
                        }
                        //判断Bean的Class上是否标识@Aspect注解
                        if (this.advisorFactory.isAspect(beanType)) {
                            aspectNames.add(beanName);
                            AspectMetadata amd = new AspectMetadata(beanType, beanName);
                            //如果@Aspect的value未赋值,默认就是PerClauseKind.SINGLETON,这些类型是动态代理生成Bean的形式
                            if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
                                MetadataAwareAspectInstanceFactory factory =
                                        new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
                                //重点看这步,此方法会花费很大篇幅,请看下一块代码(代码块5)
                                List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
                                if (this.beanFactory.isSingleton(beanName)) {
                                    //将解析的Bean名称及类上的切面缓存起来,每个Bean只解析一次
                                    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) {
            //从缓存中获取当前Bean的切面实例,如果不为空,则指明当前Bean的Class标识了@Aspect,且有切面方法
            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;
    }


}

ReflectiveAspectJAdvisorFactory反射式的切面工厂类,从@Aspect标识的类上获取@Before,@Pointcut等注解的信息及其标识的方法的信息,生成切面:
代码块5

public class ReflectiveAspectJAdvisorFactory extends AbstractAspectJAdvisorFactory implements Serializable {

    private static final Comparator<Method> METHOD_COMPARATOR;

    public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
        Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
        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<Advisor> advisors = new LinkedList<Advisor>();
        //获取标识了切面注解的方法,排除@Pointcut的方法
        for (Method method : getAdvisorMethods(aspectClass)) {
            //通过此方法,切面实例工厂,方法排序序号,及类名生成切面实例,代码详解看下一块代码(代码块6)
            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;
    }

    //获取标识了切面注解的方法
    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
                    //在@Aspect标识的类内部排除@Pointcut标识的方法,得到的方法集合包括继承自父类的方法,包括继承自Object的方法
                if (AnnotationUtils.getAnnotation(method, Pointcut.class) == null) {
                    methods.add(method);
                }
            }
        });
        //对得到的所有方法排序,
        //如果方法标识了切面注解,则按@Around, @Before, @After, @AfterReturning, @AfterThrowing的顺序排序
        //如果没有标识这些注解,则按方法名称的字符串排序,
        //有注解的方法排在无注解的方法之前
        Collections.sort(methods, METHOD_COMPARATOR);
        return methods;
    }

}

通过切面注解及其方法生成切面实例:
代码块6

public class ReflectiveAspectJAdvisorFactory extends AbstractAspectJAdvisorFactory implements Serializable {

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

        validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());
        //根据方法上的注解生成切入点
        AspectJExpressionPointcut expressionPointcut = getPointcut(
                candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
        if (expressionPointcut == null) {
            return null;
        }
        //根据方法,切入点,AOP实例工厂,类名及序号生成切面实例,在调用此构造函数时,生成通知Advice
        //此时切入点和通知均生成,构成一个完整的AOP切面,根据切入点匹配Bean,匹配生就用CGLIB生成代理对象,织入切面
        //此构造函数的代码解析请看下一块代码(代码块7)
        return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
                this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
    }

    private AspectJExpressionPointcut getPointcut(Method candidateAdviceMethod, Class<?> candidateAspectClass) {
        //查询方法上的切面注解,根据注解生成相应类型的AspectJAnnotation,在调用AspectJAnnotation的构造函数的同时
        //根据注解value或pointcut属性得到切入点表达式,有argNames则设置参数名称
        AspectJAnnotation<?> aspectJAnnotation =
                AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
        //过滤那些不含@Before, @Around, @After, @AfterReturning, @AfterThrowing注解的方法
        if (aspectJAnnotation == null) {
            return null;
        }
        //生成带表达式的切面切入点,设置其切入点表达式
        AspectJExpressionPointcut ajexp =
                new AspectJExpressionPointcut(candidateAspectClass, new String[0], new Class<?>[0]);
        ajexp.setExpression(aspectJAnnotation.getPointcutExpression());
        ajexp.setBeanFactory(this.beanFactory);
        return ajexp;
    }

}

根据切面注解标识的方法,切入点,AOP实例工厂,类名及序号生成切面实例,在调用此构造函数时,生成通知Advice,重点看如何生成通知
代码块7

public class ReflectiveAspectJAdvisorFactory extends AbstractAspectJAdvisorFactory implements Serializable {

    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;
        //根据AspectJAnnotationType的类型及注解类型生成不同的通知实例
        //同时有参数比如@AfterReturning的返回值,@AfterThrowing的异常,设置入通知中
        switch (aspectJAnnotation.getAnnotationType()) {
            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;
            case AtAround:
                springAdvice = new AspectJAroundAdvice(
                        candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
                break;
            case AtPointcut:
                if (logger.isDebugEnabled()) {
                    logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'");
                }
                return null;
            default:
                throw new UnsupportedOperationException(
                        "Unsupported advice type on method: " + candidateAdviceMethod);
        }

        // Now to configure the advice...
        //设置通知方法所属的类
        springAdvice.setAspectName(aspectName);
        //设置通知的序号,同一个类中有多个切面注解标识的方法时,按@Around, @Before, @After, @AfterReturning, @AfterThrowing的顺序排序,
        //其序号就是此方法在列表中的序号,第一个就是0
        springAdvice.setDeclarationOrder(declarationOrder);
        //获取通知方法的所有参数
        String[] argNames = this.parameterNameDiscoverer.getParameterNames(candidateAdviceMethod);
        //将通知方法上的参数设置到通知中
        if (argNames != null) {
            springAdvice.setArgumentNamesFromStringArray(argNames);
        }
        //计算参数绑定工作,此方法详解请看下一块代码(代码块8)
        springAdvice.calculateArgumentBindings();
        return springAdvice;
    }
}

切面注解标识的方法的参数有一定要求,需要和注解的类型匹配,和注解的参数名称匹配,代码详解如下:
代码块8

public abstract class AbstractAspectJAdvice implements Advice, AspectJPrecedenceInformation, Serializable {

    public synchronized final void calculateArgumentBindings() {
        // The simple case... nothing to bind.
        if (this.argumentsIntrospected || this.parameterTypes.length == 0) {
            return;
        }

        int numUnboundArgs = this.parameterTypes.length;
        Class<?>[] parameterTypes = this.aspectJAdviceMethod.getParameterTypes();
        //切面注解标识的方法第一个参数要求是JoinPoint,或StaticPart,若是@Around注解则也可以是ProceedingJoinPoint
        if (maybeBindJoinPoint(parameterTypes[0]) || maybeBindProceedingJoinPoint(parameterTypes[0])) {
            numUnboundArgs--;
        }
        else if (maybeBindJoinPointStaticPart(parameterTypes[0])) {
            numUnboundArgs--;
        }

        if (numUnboundArgs > 0) {
            // need to bind arguments by name as returned from the pointcut match
            bindArgumentsByName(numUnboundArgs);
        }

        this.argumentsIntrospected = true;
    }
    //根据方法参数,注解上的属性匹配绑定,numArgumentsExpectingToBind代表还有多少个参数需要绑定
    private void bindArgumentsByName(int numArgumentsExpectingToBind) {
        if (this.argumentNames == null) { //获取方法参数的名称
            this.argumentNames = createParameterNameDiscoverer().getParameterNames(this.aspectJAdviceMethod);
        }
        if (this.argumentNames != null) {
            // We have been able to determine the arg names.
            bindExplicitArguments(numArgumentsExpectingToBind);
        }
        else {
            throw new IllegalStateException("Advice method [" + this.aspectJAdviceMethod.getName() + "] " +
                    "requires " + numArgumentsExpectingToBind + " arguments to be bound by name, but " +
                    "the argument names were not specified and could not be discovered.");
        }
    }

    private void bindExplicitArguments(int numArgumentsLeftToBind) {
        //此属性用来存储方法未绑定的参数名称,及参数的序号
        this.argumentBindings = new HashMap<String, Integer>();

        int numExpectedArgumentNames = this.aspectJAdviceMethod.getParameterTypes().length;
        if (this.argumentNames.length != numExpectedArgumentNames) {
            throw new IllegalStateException("Expecting to find " + numExpectedArgumentNames +
                    " arguments to bind by name in advice, but actually found " +
                    this.argumentNames.length + " arguments.");
        }

        // So we match in number...,argumentIndexOffset代表第一个未绑定参数的顺序 
        int argumentIndexOffset = this.parameterTypes.length - numArgumentsLeftToBind;
        for (int i = argumentIndexOffset; i < this.argumentNames.length; i++) {
            //存储未绑定的参数名称及其顺序的映射关系
            this.argumentBindings.put(this.argumentNames[i], i);
        }

        // Check that returning and throwing were in the argument names list if
        // specified, and find the discovered argument types.
        //如果是@AfterReturning注解的returningName 有值,验证,解析,同时得到定义返回值的类型
        if (this.returningName != null) {
            if (!this.argumentBindings.containsKey(this.returningName)) {
                throw new IllegalStateException("Returning argument name '" + this.returningName +
                        "' was not bound in advice arguments");
            }
            else {
                Integer index = this.argumentBindings.get(this.returningName);
                this.discoveredReturningType = this.aspectJAdviceMethod.getParameterTypes()[index];
                this.discoveredReturningGenericType = this.aspectJAdviceMethod.getGenericParameterTypes()[index];
            }
        }
        //如果是@AfterThrowing注解的throwingName 有值,验证,解析,同时得到抛出异常的类型
        if (this.throwingName != null) {
            if (!this.argumentBindings.containsKey(this.throwingName)) {
                throw new IllegalStateException("Throwing argument name '" + this.throwingName +
                        "' was not bound in advice arguments");
            }
            else {
                Integer index = this.argumentBindings.get(this.throwingName);
                this.discoveredThrowingType = this.aspectJAdviceMethod.getParameterTypes()[index];
            }
        }

        // configure the pointcut expression accordingly.
        configurePointcutParameters(argumentIndexOffset);
    }

    private void configurePointcutParameters(int argumentIndexOffset) {
        int numParametersToRemove = argumentIndexOffset;
        if (this.returningName != null) {
            numParametersToRemove++;
        }
        if (this.throwingName != null) {
            numParametersToRemove++;
        }
        String[] pointcutParameterNames = new String[this.argumentNames.length - numParametersToRemove];
        Class<?>[] pointcutParameterTypes = new Class<?>[pointcutParameterNames.length];
        Class<?>[] methodParameterTypes = this.aspectJAdviceMethod.getParameterTypes();

        int index = 0;
        for (int i = 0; i < this.argumentNames.length; i++) {
            if (i < argumentIndexOffset) {
                continue;
            }
            if (this.argumentNames[i].equals(this.returningName) ||
                this.argumentNames[i].equals(this.throwingName)) {
                continue;
            }
            pointcutParameterNames[index] = this.argumentNames[i];
            pointcutParameterTypes[index] = methodParameterTypes[i];
            index++;
        }
        //剩余的未绑定的参数会赋值给AspectJExpressionPointcut(表达式形式的切入点)的属性,以备后续使用
        this.pointcut.setParameterNames(pointcutParameterNames);
        this.pointcut.setParameterTypes(pointcutParameterTypes);
    }

}
    原文作者:AOP
    原文地址: https://blog.csdn.net/qq_27529917/article/details/78454830
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞