基於註解的SpringAOP源碼解析(二)

上篇文章 中咱們搭建了一個閱讀源碼的demo工程,而後簡單介紹了一下@EnableAspectJAutoProxy註解,這個註解最重要的功能就是爲向Spring中注入了一個beanAnnotationAwareAspectJAutoProxyCreator,本篇文章就繼續來擼AOP的源碼spring

前文已經簡單提到了這個類的功能,不過這裏仍是要先看一下這個類的繼承圖 觀察類圖可知,AnnotationAwareAspectJAutoProxyCreator這個類間接實現了BeanPostProcessor接口。還記得咱們以前在對SpringIOC的源碼進行解析時提到過,Spring在實例化Bean的先後會分別調用方法postProcessBeforeInstantiationpostProcessAfterInstantiation 而AOP的總體邏輯就是經過這兩個方法來實現的express

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;
    }

一個長方法buildAspectJAdvisorside

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;
    }

調用生成加強實例的方法post

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);
	}

生成加強ui

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;
    }
}

校驗方法參數並綁定this

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);
    }

未完待續 限於平臺字數限制,本篇文章就到這裏

1

相關文章
相關標籤/搜索