基于注解的SpringAOP源码解析二

7次阅读

共计 15566 个字符,预计需要花费 39 分钟才能阅读完成。

在上篇文章
中我们搭建了一个阅读源码的 demo 工程,然后简单介绍了一下 @EnableAspectJAutoProxy 注解,这个注解最重要的功能就是为向 Spring 中注入了一个 beanAnnotationAwareAspectJAutoProxyCreator, 本篇文章就继续来撸 AOP 的源码

前文已经简单提到了这个类的功能,不过这里还是要先看一下这个类的继承图

观察类图可知,AnnotationAwareAspectJAutoProxyCreator 这个类间接实现了 BeanPostProcessor 接口。还记得我们之前在对 SpringIOC 的源码进行解析时提到过,Spring 在实例化 Bean 的前后会分别调用方法 postProcessBeforeInstantiationpostProcessAfterInstantiation
而 AOP 的整体逻辑就是通过这两个方法来实现的

postProcessBeforeInstantiation

首先看一下这个 postProcessBeforeInstantiation 方法,它是在 bean 实例化之前调用的,主要是针对切面类。这个方法不在 AnnotationAwareAspectJAutoProxyCreator 这个类中,而是在其父类 AbstractAutoProxyCreator 中

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

        if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {if (this.advisedBeans.containsKey(cacheKey)) {return null;}
            // 加载所有增强
            if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {this.advisedBeans.put(cacheKey, Boolean.FALSE);
                return null;
            }
        }

        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;
    }
加载增强

上方代码中最重要的一个方法就是 shouldSkip 方法了,这个方法被 AspectJAwareAdvisorAutoProxyCreator 所重载

protected boolean shouldSkip(Class<?> beanClass, String beanName) {
  
    // 查找所有标识了 @Aspect 注解的类,这里是重点,接着往下看
    List<Advisor> candidateAdvisors = findCandidateAdvisors();
    for (Advisor advisor : candidateAdvisors) {if (advisor instanceof AspectJPointcutAdvisor) {if (((AbstractAspectJAdvice) advisor.getAdvice()).getAspectName().equals(beanName)) {return true;}
        }
    }
    return super.shouldSkip(beanClass, beanName);
    }


    protected List<Advisor> findCandidateAdvisors() {return this.advisorRetrievalHelper.findAdvisorBeans();
    }
    
    protected List<Advisor> findCandidateAdvisors() {List<Advisor> advisors = super.findCandidateAdvisors();
        //buildAspectJAdvisors 是重点
           advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
        return advisors;
    }

一个长方法 buildAspectJAdvisors

    public List<Advisor> buildAspectJAdvisors() {
    // 所有 Aspect 类的名称集合
        List<String> aspectNames = this.aspectBeanNames;
        if (aspectNames == null) {synchronized (this) {
                aspectNames = this.aspectBeanNames;
                // 这个双重检查是不是在学习安全的单例模式的时候见过
                if (aspectNames == null) {List<Advisor> advisors = new LinkedList<Advisor>();
                    aspectNames = new LinkedList<String>();
                    // 获取所有 Bean 名称
                    String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.beanFactory, Object.class, true, false);
                    for (String beanName : beanNames) {
                        // 判断是否符合条件,比如说有时会排除一些类,不让这些类注入进 Spring
                        if (!isEligibleBean(beanName)) {continue;}
               
                        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);
                            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)) {
                                    // 将解析的 Bean 名称及类上的增强缓存起来, 每个 Bean 只解析一次
                                    this.advisorsCache.put(beanName, classAdvisors);
                                }
                                else {this.aspectFactoryCache.put(beanName, factory);
                                }
                                advisors.addAll(classAdvisors);
                            }
                            else {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;
    }

生成增强

advisorFactory.getAdvisors 方法会从 @Aspect 标识的类上获取 @Before,@Pointcut 等注解的信息及其标识的方法的信息,生成增强

    public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
        String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();
        // 校验类的合法性相关
        validate(aspectClass);

        MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
                new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);

        List<Advisor> advisors = new LinkedList<Advisor>();
        // 获取这个类所有的增强方法
        for (Method method : getAdvisorMethods(aspectClass)) {
            // 生成增强实例
            Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, advisors.size(), aspectName);
            if (advisor != null) {advisors.add(advisor);
            }
        }

        if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);
            advisors.add(0, instantiationAdvisor);
        }

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

调用生成增强实例的方法


    public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
            int declarationOrderInAspect, String aspectName) {
        // 再次校验类的合法性
        validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());
        // 切点表达式的包装类里面包含这些东西:execution(public * cn.shiyujun.service.IOCService.hollo(..))
        AspectJExpressionPointcut expressionPointcut = getPointcut(candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
        if (expressionPointcut == null) {return null;}
        // 根据方法、切点、AOP 实例工厂、类名、序号生成切面实例,详细代码往下看
        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;
    }

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()) {
            Pointcut preInstantiationPointcut = Pointcuts.union(aspectInstanceFactory.getAspectMetadata().getPerClausePointcut(), this.declaredPointcut);

            this.pointcut = new PerTargetInstantiationModelPointcut(this.declaredPointcut, preInstantiationPointcut, aspectInstanceFactory);
            this.lazy = true;
        }
        else {
            this.pointcut = this.declaredPointcut;
            this.lazy = false;
            // 重点在这里
            this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut);
        }
    }
    
    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);
    }

生成增强

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 (!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, 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);
        }

        // 设置通知方法所属的类
        springAdvice.setAspectName(aspectName);
        // 设置通知的序号, 同一个类中有多个切面注解标识的方法时, 按上方说的排序规则来排序,// 其序号就是此方法在列表中的序号,第一个就是 0
        springAdvice.setDeclarationOrder(declarationOrder);
        // 获取通知方法的所有参数
        String[] argNames = this.parameterNameDiscoverer.getParameterNames(candidateAdviceMethod);
        // 将通知方法上的参数设置到通知中
        if (argNames != null) {springAdvice.setArgumentNamesFromStringArray(argNames);
        }
        // 计算参数绑定工作,此方法详解请接着往下看
        springAdvice.calculateArgumentBindings();
        return springAdvice;
    }
}

校验方法参数并绑定

    public synchronized final void calculateArgumentBindings() {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) {
        // 绑定属性
            bindArgumentsByName(numUnboundArgs);
        }

        this.argumentsIntrospected = true;
    }
    private void bindArgumentsByName(int numArgumentsExpectingToBind) {if (this.argumentNames == null) { // 获取方法参数的名称
            this.argumentNames = createParameterNameDiscoverer().getParameterNames(this.aspectJAdviceMethod);
        }
        if (this.argumentNames != null) {
            // 往下看
            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);
    }

未完待续
限于平台字数限制,本篇文章就到这里

正文完
 0