Spring AOPソースの解読2-カットと強化の取得

30176 ワード

前言
前の文章では代理処理の入口を紹介しました.この章では代理処理の流れの一つを紹介します.
本文
まず、getAdvicesAndAdvisorsForBean方法の内容を見て、この方法の実現はサブクラスAbstractAdvisorAutoProxyCreatorにおいて行われる.この方法の中の主なロジックはfindEligible Advisors方法の中にあります.
protected Object[] getAdvicesAndAdvisorsForBean(Class> beanClass, String beanName, TargetSource targetSource) {
    List advisors = findEligibleAdvisors(beanClass, beanName);
    if (advisors.isEmpty()) {
        return DO_NOT_PROXY;
    }
    return advisors.toArray();
}
findEligible Advisorsの主なロジックは以下の二つの方法です.
  • findCandCadidateAdvisors:適切なAdvisorを検索します.
  • findAdvisors ThatCanply:AdvisorがBeanに使われているかどうかを見てください.(AdvisorのPointCutによって判断します.)
  • protected List findEligibleAdvisors(Class> beanClass, String beanName) {
        //      Advisor
        List candidateAdvisors = findCandidateAdvisors();
        //   Advisor     Bean 
        List eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
        extendAdvisors(eligibleAdvisors);
        if (!eligibleAdvisors.isEmpty()) {
            eligibleAdvisors = sortAdvisors(eligibleAdvisors);
        }
        return eligibleAdvisors;
    }
    1、findCandCadidateA dvisorsが取得した関連プロセス:
    findCandCanddidateAdvisors方法については、AsppectJの関連する処理を分析していますので、この方法はAnnotationAwareAspect AutoxyCreator類において実現されたものです.
    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.
        //  BeanFactory         ,   Spring     (Advisor),      
        advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
        return advisors;
    }
    public List buildAspectJAdvisors() {
        List aspectNames = null;
    
        synchronized (this) {
            aspectNames = this.aspectBeanNames;
            if (aspectNames == null) {
                List advisors = new LinkedList();
                aspectNames = new LinkedList();
    
                // beanNamesForTypeIncludingAncestors          bean,
                //             (        Object,      )
                //    DefaultListableBeanFactory#doGetBeanNamesForType   
                //         Class#isAssignableFrom  
                String[] beanNames =
    BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.beanFactory, Object.class, true, false);
                for (String beanName : beanNames) {
                    //   Bean   ,       
                    //            ,       。
                    // DefaultAdvisorAutoProxyCreator  ,      ,!isUsePrefix()    True,        True
                    //            AbstractBeanFactory#isTypeMatch  
                    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> beanType = this.beanFactory.getType(beanName);
                    if (beanType == null) {
                        continue;
                    }
    
                    //   beanType 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);
    
                            //   Aspect        ,    Advisors。
                            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 LinkedList();
        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;
    }
    上のステップの中で最も重要で煩雑なのは、通知器の取得である.この機能はソースコードを見て、AsppectJAdvice FactoryインターフェースのgetAdvisors方法で完成しました.私たちはAspectJAdvice Factoryインターフェースの継承関係に基づいて、Reflective AsppectJAdvisors Factory類の中で彼のgetAdvisors実現類を見つけました.
    public List getAdvisors(MetadataAwareAspectInstanceFactory maaif) {
        final Class> aspectClass = maaif.getAspectMetadata().getAspectClass();
        final String aspectName = maaif.getAspectMetadata().getAspectName();
        validate(aspectClass);
    
        // We need to wrap the MetadataAwareAspectInstanceFactory with a decorator
        // so that it will only instantiate once.
        final MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
                new LazySingletonAspectInstanceFactoryDecorator(maaif);
    
        final List advisors = new LinkedList();
        //  aspectClass               (  PointCut       ),  Advisor,       。
        // (        Advice,               PointCut,   Advisor)
        for (Method method : getAdvisorMethods(aspectClass)) {
            Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, advisors.size(), aspectName);
            if (advisor != null) {
                advisors.add(advisor);
            }
        }
    
        // If it's a per target aspect, emit the dummy instantiating aspect.
        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;
    }
    //     ,          ,        ,      Method     ,     ,       。
    private List getAdvisorMethods(Class> aspectClass) {
        final List methods = new LinkedList();
        ReflectionUtils.doWithMethods(aspectClass, new ReflectionUtils.MethodCallback() {
            @Override
            public void doWith(Method method) throws IllegalArgumentException {
                // Exclude pointcuts
                if (AnnotationUtils.getAnnotation(method, Pointcut.class) == null) {
                    methods.add(method);
                }
            }
        });
        Collections.sort(methods, METHOD_COMPARATOR);
        return methods;
    }
    一般的なブースターの取得ロジックは、getAdvisor法により実現され、このステップは、接点に対する注釈と注釈情報に基づいて強調を生成するステップを含む.
    public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aif,
            int declarationOrderInAspect, String aspectName) {
    
        validate(aif.getAspectMetadata().getAspectClass());
        //   PointCut  (   PointCut     )
        //  Method          ,  Method      ,           
        //     ,  null;   ,    PointCut      
        //      :Before.class, Around.class, After.class, AfterReturning.class, AfterThrowing.class, Pointcut.class
        AspectJExpressionPointcut ajexp =
                getPointcut(candidateAdviceMethod, aif.getAspectMetadata().getAspectClass());
        if (ajexp == null) {
            return null;
        }
        //   PointCut       
        return new InstantiationModelAwarePointcutAdvisorImpl(
                this, ajexp, aif, candidateAdviceMethod, declarationOrderInAspect, aspectName);
    }
    private AspectJExpressionPointcut getPointcut(Method candidateAdviceMethod, Class> candidateAspectClass) {
        //         
        //   Method      ,           ,      null
        //      :Before.class, Around.class, After.class, AfterReturning.class, AfterThrowing.class, Pointcut.class
        AspectJAnnotation> aspectJAnnotation =
    AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
        if (aspectJAnnotation == null) {
            return null;
        }
        //   AspectJExpressionPointcut          
        AspectJExpressionPointcut ajexp =
                new AspectJExpressionPointcut(candidateAspectClass, new String[0], new Class>[0]);
    
        //              :
        // @Pointcut("execution(* test.TestBean.*(..))")
        ajexp.setExpression(aspectJAnnotation.getPointcutExpression());
        return ajexp;
    }
    protected static AspectJAnnotation> findAspectJAnnotationOnMethod(Method method) {
        //          ,                   
        Class>[] classesToLookFor = new Class>[] {
                Before.class, Around.class, After.class, AfterReturning.class, AfterThrowing.class, Pointcut.class};
        for (Class> c : classesToLookFor) {
            AspectJAnnotation> foundAnnotation = findAnnotation(method, (Class) c);
            if (foundAnnotation != null) {
                return foundAnnotation;
            }
        }
        return null;
    }
    //               AspectJAnnotation   
    private static AsppectJAnnotationfindAnnotation(Method method、Class)tolook For){
    A result=AnnotationUtils.findAnnotation;
    if(result!=null){
    return new Aspect JAnnotation(レスリング)
    )
    else{
    return null
    )
    )
    上記のgetAdvisor方法の最後の行のコードは、接点情報に基づいてエンハンスを生成するreturn new InstantiationModelAwarePointcutAdvisorImpl(
    this, ajexp, aif, candidateAdviceMethod, declarationOrderInAspect, aspectName)
    である.すべての拡張は、Advisorの実装クラスInstantiationModelAwarePointcutAdvisorImplによって統一的にカプセル化されている.
    public InstantiationModelAwarePointcutAdvisorImpl(AspectJAdvisorFactory af, AspectJExpressionPointcut ajexp,
            MetadataAwareAspectInstanceFactory aif, Method method, int declarationOrderInAspect, String aspectName) {
    
        this.declaredPointcut = ajexp;
        this.method = method;
        this.atAspectJAdvisorFactory = af;
        this.aspectInstanceFactory = aif;
        this.declarationOrder = declarationOrderInAspect;
        this.aspectName = aspectName;
    
        if (aif.getAspectMetadata().isLazilyInstantiated()) {
            // Static part of the pointcut is a lazy type.
            Pointcut preInstantiationPointcut =
                    Pointcuts.union(aif.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, aif);
            this.lazy = true;
        }
        else {
            // A singleton aspect.
            //    Advice
            this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut);
            this.pointcut = declaredPointcut;
            this.lazy = false;
        }
    }
    パッケージプロセスでは、単にクラスのインスタンスに情報をカプセル化するだけで、すべての情報は単純に値を割り当て、インスタンス初期化のプロセスでは、ブースターの初期化も完了した.異なる強化によって具現される論理は異なるので、注釈中の情報によって初期化される対応するブースターはinstantiateAdvice方法で完成される.
    private Advice instantiateAdvice(AspectJExpressionPointcut pcut) {
        return this.atAspectJAdvisorFactory.getAdvice(
            this.method, pcut, this.aspectInstanceFactory, this.declarationOrder, this.aspectName);
    }
    public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut ajexp,
        MetadataAwareAspectInstanceFactory aif, int declarationOrderInAspect, String aspectName) {
    
        Class> candidateAspectClass = aif.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 AtBefore:
                springAdvice = new AspectJMethodBeforeAdvice(candidateAdviceMethod, ajexp, aif);
                break;
            case AtAfter:
                springAdvice = new AspectJAfterAdvice(candidateAdviceMethod, ajexp, aif);
                break;
            case AtAfterReturning:
                springAdvice = new AspectJAfterReturningAdvice(candidateAdviceMethod, ajexp, aif);
                AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation();
                if (StringUtils.hasText(afterReturningAnnotation.returning())) {
                    springAdvice.setReturningName(afterReturningAnnotation.returning());
                }
                break;
            case AtAfterThrowing:
                springAdvice = new AspectJAfterThrowingAdvice(candidateAdviceMethod, ajexp, aif);
                AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation();
                if (StringUtils.hasText(afterThrowingAnnotation.throwing())) {
                    springAdvice.setThrowingName(afterThrowingAnnotation.throwing());
                }
                break;
            case AtAround:
                springAdvice = new AspectJAroundAdvice(candidateAdviceMethod, ajexp, aif);
                break;
            case AtPointcut:
                if (logger.isDebugEnabled()) {
                    logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'");
                }
                return null;
            default:
                throw new UnsupportedOperationException(
                        "Unsupported advice type on method " + candidateAdviceMethod);
    }
    2,findAdvisors ThaCanply関連プロセス
    findCandCadidateAdvisorsは名前のマッチングを通して、適当なAdvisorを見つけました.findAdvisors ThaCanplyの方法を見に来ました.この方法はPointCutによってターゲットクラスが代理対象の条件に合致しているかどうかを確認し、該当する場合はAdvisorを集合に追加し、最後に集合に戻ります.
    public static List findAdvisorsThatCanApply(List candidateAdvisors, Class> clazz) {
        if (candidateAdvisors.isEmpty()) {
            return candidateAdvisors;
        }
        List eligibleAdvisors = new LinkedList();
        //          IntroductionAdvisor   Advisor,      
        for (Advisor candidate : candidateAdvisors) {
            if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
                eligibleAdvisors.add(candidate);
            }
        }
        boolean hasIntroductions = !eligibleAdvisors.isEmpty();
        //        IntroductionAdvisor   Advisor
        for (Advisor candidate : candidateAdvisors) {
            if (candidate instanceof IntroductionAdvisor) {
                // already processed
                continue;
            }
            //          
            if (canApply(candidate, clazz, hasIntroductions)) {
                eligibleAdvisors.add(candidate);
            }
        }
        return eligibleAdvisors;
    }
    
       //   Advisor    ,       ,         PointCut  
    public static boolean canApply(Advisor advisor, Class> targetClass, boolean hasIntroductions) {
        if (advisor instanceof IntroductionAdvisor) {
            return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass);
        }
        // PointCut   Advisor     
        else if (advisor instanceof PointcutAdvisor) {
            PointcutAdvisor pca = (PointcutAdvisor) advisor;
            return canApply(pca.getPointcut(), targetClass, hasIntroductions);
        }
        else {
            // It doesn't have a pointcut so we assume it applies.
            return true;
        }
    }
    //       ,        PointCut     
    public static boolean canApply(Pointcut pc, Class> targetClass, boolean hasIntroductions) {
        Assert.notNull(pc, "Pointcut must not be null");
        if (!pc.getClassFilter().matches(targetClass)) {
            return false;
        }
    
        MethodMatcher methodMatcher = pc.getMethodMatcher();
        IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
        if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
            introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
        }
    
        Set> classes = new LinkedHashSet>(ClassUtils.getAllInterfacesForClassAsSet(targetClass));
        classes.add(targetClass);
        for (Class> clazz : classes) {
            Method[] methods = clazz.getMethods();
            for (Method method : methods) {
                if ((introductionAwareMethodMatcher != null &&
                        introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions)) ||
                        methodMatcher.matches(method, targetClass)) {
                    return true;
                }
            }
        }
    
        return false;
    }
    ここで、うどんと補強の取得に関するロジックを説明しました.次の章では、どのようにうどんを見つけて代理を作るかを説明します.