loadBeanDefinitions方法源碼跟蹤(三)

由於字數超過了限制,因此分紅了三篇,承接上篇:
https://www.jianshu.com/p/46e27afd7d96java

代碼過寬,能夠shift + 鼠標滾輪 左右滑動查看node

4.parseCustomElement

<!-- 事務處理,事務只針對service層 -->
<aop:config>
    <aop:pointcut id="pc" expression="execution(public * cn.mrdear.service.impl..*(..))" />
    <aop:advisor pointcut-ref="pc" advice-ref="txAdvice" />
</aop:config>

非默認名稱空間的標籤,走的是這個方法spring

//4.若是該標籤屬於其餘的名稱空間好比:context,aop等
//xmlns:aop="http://www.springframework.org/schema/aop"
//xmlns:context="http://www.springframework.org/schema/context"
delegate.parseCustomElement(ele);

進入這個方法,在BeanDefinitionParserDelegate類中express

public BeanDefinition parseCustomElement(Element ele) {
    return parseCustomElement(ele, null);
}


public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {
    
    //拿到標籤對應的名稱空間URI
    //好比:http://www.springframework.org/schema/aop
    String namespaceUri = getNamespaceURI(ele);
    
    //4.1拿到名稱空間處理器解析器,去解析URI,獲取名稱空間處理器
    NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
    if (handler == null) {
        error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
        return null;
    }
    
    //4.2經過處理器的某個解析器解析對應標籤
    return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
}

4.1 resolve

DefaultNamespaceHandlerResolver是名稱空間處理器解析器的默認實現app

跟蹤標記4.1的方法ide

//4.1拿到名稱空間處理器解析器,去解析URI,獲取名稱空間處理器
NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);


/**
* Locate the {@link NamespaceHandler} for the supplied namespace URI
* from the configured mappings.
*
* 根據提供的 namespace URI 從配置映射中找到 NamespaceHandler
*/
@Override
public NamespaceHandler resolve(String namespaceUri) {
    
    //拿處處理器解析器中全部的處理器
    Map<String, Object> handlerMappings = getHandlerMappings();
    
    //拿到指定的處理器
    Object handlerOrClassName = handlerMappings.get(namespaceUri);
    
    //若是爲null就返回null
    if (handlerOrClassName == null) {
        return null;
    }
    
    //若是是實例就返回實例
    else if (handlerOrClassName instanceof NamespaceHandler) {
        return (NamespaceHandler) handlerOrClassName;
    }
    
    //不然就必定是字符串
    else {
        String className = (String) handlerOrClassName;
        try {
            
            //經過加載器生成處理器的Class對象
            Class<?> handlerClass = ClassUtils.forName(className, this.classLoader);
            
            //必需要實現NamespaceHandler接口
            if (!NamespaceHandler.class.isAssignableFrom(handlerClass)) {
                throw new FatalBeanException("Class [" + className + "] for namespace [" + namespaceUri +
                                             "] does not implement the [" + NamespaceHandler.class.getName() + "] interface");
            }
            
            //實例化一個
            NamespaceHandler namespaceHandler = (NamespaceHandler) BeanUtils.instantiateClass(handlerClass);
            
            //初始化,進入這個方法,裏面初始化多個解析器
            namespaceHandler.init();
            
            //用實例覆蓋原先handlerMappings中的字符串
            handlerMappings.put(namespaceUri, namespaceHandler);
            return namespaceHandler;
        }
        catch (ClassNotFoundException ex) {
            throw new FatalBeanException("NamespaceHandler class [" + className + "] for namespace [" +
                                         namespaceUri + "] not found", ex);
        }
        catch (LinkageError err) {
            throw new FatalBeanException("Invalid NamespaceHandler class [" + className + "] for namespace [" +
                                         namespaceUri + "]: problem with handler class file or dependent class", err);
        }
    }
}



/**
* 這個方法在類AopNamespaceHandler中
*
* Register the {@link BeanDefinitionParser BeanDefinitionParsers} for the
* '{@code config}', '{@code spring-configured}', '{@code aspectj-autoproxy}'
* and '{@code scoped-proxy}' tags.
*
* 爲config、spring-configured、aspectj-autoproxy以及scoped-proxy標籤註冊BeanDefinitionParsers
*/
@Override
public void init() {
    
    //這裏面每個解析器都對應着AOP名稱空間下的一個標籤
    //不一樣的處理器註冊的解析器都不同
    //這裏隨便找一個解析器,查看他的註冊流程
    
    // In 2.0 XSD as well as in 2.1 XSD.
    registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser());
    registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());
    registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator());

    // Only in 2.0 XSD: moved to context namespace as of 2.1
    registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
}

/**
* 此方法在類AopNamespaceHandler的父類NamespaceHandlerSupport中
*
* Subclasses can call this to register the supplied {@link BeanDefinitionParser} to
* handle the specified element. The element name is the local (non-namespace qualified)
* name.
*
* 子類能夠調用這個方法註冊指定的BeanDefinitionParser去處理相關的標籤
* 這個elementName是個局部名稱(不包含名稱空間)
*/
protected final void registerBeanDefinitionParser(String elementName, BeanDefinitionParser parser) {
    
    //將解析器註冊到這個名稱空間處理器的parsers屬性中,
    //parsers是一個HashMap
    this.parsers.put(elementName, parser);
}

4.2 parse

跟蹤標記4.2的方法oop

進入處理器的抽象父類NamespaceHandlerSupport中ui

入參傳遞了一個ParserContext解析器上下文,ParserContext中拿到了閱讀器上下文的引用,代理的引用,containingBd在這裏爲nullthis

//4.2經過處理器的某個解析器解析對應標籤
return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));

/**
* Parses the supplied {@link Element} by delegating to the {@link BeanDefinitionParser} that is
* registered for that {@link Element}.
*
* 經過委派給根據對應標籤所註冊的解析器,來解析提供的標籤
*/
@Override
public BeanDefinition parse(Element element, ParserContext parserContext) {
    
    //將標籤名稱做爲key,去處理器內部的parsers屬性中,獲取對應的value值,也就是解析器
    //利用解析器來解析這個標籤,進入這個方法。
    return findParserForElement(element, parserContext).parse(element, parserContext);
}


/**
* 由於解析是的<aop:config>,因此該方法在ConfigBeanDefinitionParser類中
*
* Parse the specified {@link Element} and register the resulting
* {@link BeanDefinition BeanDefinition(s)} with the
* {@link org.springframework.beans.factory.xml.ParserContext#getRegistry() BeanDefinitionRegistry}
* embedded in the supplied {@link ParserContext}.
* <p>Implementations must return the primary {@link BeanDefinition} that results
* from the parse if they will ever be used in a nested fashion (for example as
* an inner tag in a {@code <property/>} tag). Implementations may return
* {@code null} if they will <strong>not</strong> be used in a nested fashion.
*
* 解析指定的標籤,並註冊最終的結果bean Definition到內嵌在ParserContext中的bean工廠中
*/
@Override
public BeanDefinition parse(Element element, ParserContext parserContext) {
    
    //一個組件集合,裏面包含了多個組件,以標籤名(包含了名稱空間)做爲名稱,好比aop:config
    //裏面包含的多個組件就是aop:config的子標籤,包含對標籤屬性的描述
    //好比xml中pointcut子標籤就是一個組件,advisor子標籤也是一個組件
    //這個組件記錄了子標籤的name屬性或者expression屬性,根據不一樣子標籤,屬性不同
    CompositeComponentDefinition compositeDef =
        new CompositeComponentDefinition(element.getTagName(), parserContext.extractSource(element));
    
    //將組件集合保存在parserContext解析器上下文的containingComponents屬性中
    parserContext.pushContainingComponent(compositeDef);
    
    //4.2.1配置自動代理建立器
    configureAutoProxyCreator(parserContext, element);
    
    //配置完建立器後拿到全部子標籤
    List<Element> childElts = DomUtils.getChildElements(element);
    
    for (Element elt: childElts) {
        
        //拿到全部子標籤localName,也就是不包括名稱空間的標籤名字
        String localName = parserContext.getDelegate().getLocalName(elt);
        
        //若是子標籤是pointcut
        if (POINTCUT.equals(localName)) {
            
            //4.2.2解析pointcut子標籤
            parsePointcut(elt, parserContext);
        }
        
        //若是子標籤是advisor
        else if (ADVISOR.equals(localName)) {

            //4.2.3解析advisor子標籤
            parseAdvisor(elt, parserContext);
        }
        
         //若是子標籤是aspect
        else if (ASPECT.equals(localName)) {

            //4.2.4解析aspect子標籤
            parseAspect(elt, parserContext);
        }
    }
    
    //4.2.5彈出組件
    parserContext.popAndRegisterContainingComponent();
    return null;
}

4.2.1 configureAutoProxyCreator

跟蹤標記4.2.1的方法spa

此方法在類ConfigBeanDefinitionParser中實現

//4.2.1配置自動代理建立器
configureAutoProxyCreator(parserContext, element);

/**
* Configures the auto proxy creator needed to support the {@link BeanDefinition BeanDefinitions}
* created by the '{@code <aop:config/>}' tag. Will force class proxying if the
* '{@code proxy-target-class}' attribute is set to '{@code true}'.
* 
* 配置自動代理建立器,支持由<aop:config/>標籤建立的beanDefinition
* 若是標籤的proxy-target-class屬性被設置爲true,那麼強制代理
*/
private void configureAutoProxyCreator(ParserContext parserContext, Element element) {
    AopNamespaceUtils.registerAspectJAutoProxyCreatorIfNecessary(parserContext, element);
}

/**
* 進入AopNamespaceUtils類中的靜態方法
*/
public static void registerAspectJAutoProxyCreatorIfNecessary(
    ParserContext parserContext, Element sourceElement) {
    
   //4.2.1.1若是必要的話註冊AspectJ自動代理建立器
    BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAutoProxyCreatorIfNecessary(
        parserContext.getRegistry(), parserContext.extractSource(sourceElement));
    
    //4.2.1.2若是必要的話使用CLass代理
    useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
    
    //4.2.1.3若是必要的話註冊組件
    registerComponentIfNecessary(beanDefinition, parserContext);
}
4.2.1.1 registerAspectJAutoProxyCreatorIfNecessary

先跟蹤標記4.2.1.1的方法

該方法在AopConfigUtils類中實現

//4.2.1.1若是必要的話註冊AspectJ自動代理建立器
BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAutoProxyCreatorIfNecessary(
    parserContext.getRegistry(), parserContext.extractSource(sourceElement));


public static BeanDefinition registerAspectJAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, Object source) {
    
    //傳遞了一個AspectJAwareAdvisorAutoProxyCreator的Class,進入這個方法
    return registerOrEscalateApcAsRequired(AspectJAwareAdvisorAutoProxyCreator.class, registry, source);
}


private static BeanDefinition registerOrEscalateApcAsRequired(Class<?> cls, BeanDefinitionRegistry registry, Object source) {
    Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
   
    //工廠中是否已經註冊了org.springframework.aop.config.internalAutoProxyCreator
    if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
        BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
       
        //若是已經有註冊了internalAutoProxyCreator,而且和入參傳遞的不是同一個Class,
        //那麼就根據優先級進行選擇
        if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
            
            //類AopConfigUtils中有個ArrayList屬性APC_PRIORITY_LIST,在類靜態構造中依次加入了
            //幾個建立器,這個方法就是查找某個建立器在APC_PRIORITY_LIST中的索引,若是沒有找到就報錯
            int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
            int requiredPriority = findPriorityForClass(cls);
           
            //internalAutoProxyCreator的索引爲0,入參的AspectJAwareAdvisorAutoProxyCreator
            //索引爲1,後者要大,因此從新設置下apcDefinition的beanClass
            if (currentPriority < requiredPriority) {
                apcDefinition.setBeanClassName(cls.getName());
            }
        }
        
        //直接返回null
        return null;
    }
    RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
    beanDefinition.setSource(source);
    beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
    beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
    registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
    return beanDefinition;
}
4.2.1.2 useClassProxyingIfNecessary

跟蹤標記4.2.1.2

此方法的實如今AopNamespaceUtils類中

//4.2.1.2若是必要的話使用CLass代理
useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);

private static void useClassProxyingIfNecessary(BeanDefinitionRegistry registry, Element sourceElement) {
    if (sourceElement != null) {
        
        //查看是否有設置proxy-target-class屬性
        boolean proxyTargetClass = Boolean.valueOf(sourceElement.getAttribute(PROXY_TARGET_CLASS_ATTRIBUTE));
        if (proxyTargetClass) {
            AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
        }
        
        //查看是否有設置expose-proxy屬性
        boolean exposeProxy = Boolean.valueOf(sourceElement.getAttribute(EXPOSE_PROXY_ATTRIBUTE));
        if (exposeProxy) {
            AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
        }
    }
}
4.2.1.3 registerComponentIfNecessary

跟蹤標記4.2.1.3

此方法的實如今AopNamespaceUtils類中

//4.2.1.3若是必要的話註冊組件
registerComponentIfNecessary(beanDefinition, parserContext);

private static void registerComponentIfNecessary(BeanDefinition beanDefinition, ParserContext parserContext) {
    
    //由於前面建立器中的beanClass用了新的那個,因此返回的beanDefinition爲null,
    //這裏的beanDefinition也就爲null了,跳過
    if (beanDefinition != null) {
        BeanComponentDefinition componentDefinition =
            new BeanComponentDefinition(beanDefinition, AopConfigUtils.AUTO_PROXY_CREATOR_BEAN_NAME);
        parserContext.registerComponent(componentDefinition);
    }
}

4.2.2 parsePointcut

跟蹤標記4.2.2

此方法的實如今ConfigBeanDefinitionParser類中

//4.2.2解析pointcut子標籤
parsePointcut(elt, parserContext);

/**
* Parses the supplied {@code <pointcut>} and registers the resulting
* Pointcut with the BeanDefinitionRegistry.
* 
* 解析<pointcut>標籤,註冊結果到bean工廠中
*/
private AbstractBeanDefinition parsePointcut(Element pointcutElement, ParserContext parserContext) {
    
    //拿到id和expression的屬性
    String id = pointcutElement.getAttribute(ID);
    String expression = pointcutElement.getAttribute(EXPRESSION);

    AbstractBeanDefinition pointcutDefinition = null;

    try {
        
        //解析前放入,解析後彈出
        this.parseState.push(new PointcutEntry(id));
        
        //建立一個bean definition,提早指定AspectJExpressionPointcut.class爲beanClass
        //默認多例,同步,將expression添加到bean definition的propertyValues中
        pointcutDefinition = createPointcutDefinition(expression);
       
        //這裏走null
        pointcutDefinition.setSource(parserContext.extractSource(pointcutElement));
        
        String pointcutBeanName = id;
        
        //有無id走不一樣方法
        if (StringUtils.hasText(pointcutBeanName)) {
            
            //走的工廠註冊方法,上面跟蹤過,能夠回看3.3.1標記
            parserContext.getRegistry().registerBeanDefinition(pointcutBeanName, pointcutDefinition);
        }
        else {
            pointcutBeanName = parserContext.getReaderContext().registerWithGeneratedName(pointcutDefinition);
        }
        
        //註冊組件,進入這個方法查看
        parserContext.registerComponent(
            new PointcutComponentDefinition(pointcutBeanName, pointcutDefinition, expression));
    }
    finally {
        
        //解析前放入,解析後彈出
        this.parseState.pop();
    }

    return pointcutDefinition;
}

/**
* 此方法的實如今ParserContext類中
*/
public void registerComponent(ComponentDefinition component) {
    
    //拿到parserContext中containingComponents屬性裏的最後一個元素
    //這個元素是在4.2標記中parse方法裏被放入,組件名稱叫作aop:config
    CompositeComponentDefinition containingComponent = getContainingComponent();
    if (containingComponent != null) {
       
        //增長嵌套的組件,進入這個方法
        containingComponent.addNestedComponent(component);
    }
    else {
        this.readerContext.fireComponentRegistered(component);
    }
}

/**
* 這個方法在CompositeComponentDefinition類中
*
* Add the given component as nested element of this composite component.
*
* 增長指定的組件,做爲這個組件的嵌套元素
*/
public void addNestedComponent(ComponentDefinition component) {
    Assert.notNull(component, "ComponentDefinition must not be null");
    
    //也就是在CompositeComponentDefinition類中的nestedComponents屬性中,
    //將入參的component添加進去
    //nestedComponents是一個LinkedList
    this.nestedComponents.add(component);
}

4.2.3 parseAdvisor

跟蹤標記4.2.3

此方法的實如今ConfigBeanDefinitionParser類中

//4.2.3若是子標籤是advisor
parseAdvisor(elt, parserContext);

/**
* Parses the supplied {@code <advisor>} element and registers the resulting
* {@link org.springframework.aop.Advisor} and any resulting {@link org.springframework.aop.Pointcut}
* with the supplied {@link BeanDefinitionRegistry}.
*
* 解析 <advisor> 標籤,並註冊 Advisor 結果和其餘 Pointcut 結果到工廠中
*/
private void parseAdvisor(Element advisorElement, ParserContext parserContext) {
    
    // 4.2.3.1 建立一個顧問的 BeanDefinition
    AbstractBeanDefinition advisorDef = createAdvisorBeanDefinition(advisorElement, parserContext);
    String id = advisorElement.getAttribute(ID);

    try {
        this.parseState.push(new AdvisorEntry(id));
        String advisorBeanName = id;
        if (StringUtils.hasText(advisorBeanName)) {
            
            // 註冊到工廠
            parserContext.getRegistry().registerBeanDefinition(advisorBeanName, advisorDef);
        }
        else {
            
            // 沒有 id 屬性,生成默認規則的名字再註冊到工廠
            advisorBeanName = parserContext.getReaderContext().registerWithGeneratedName(advisorDef);
        }

        // 4.2.3.2 解析切入點屬性
        Object pointcut = parsePointcutProperty(advisorElement, parserContext);
        
        // advisorDef 添加 pointcut 等屬性,而後將 advisorDef 註冊到組件組合定義中
        if (pointcut instanceof BeanDefinition) {
            advisorDef.getPropertyValues().add(POINTCUT, pointcut);
            parserContext.registerComponent(
                new AdvisorComponentDefinition(advisorBeanName, advisorDef, (BeanDefinition) pointcut));
        }
        else if (pointcut instanceof String) {
            advisorDef.getPropertyValues().add(POINTCUT, new RuntimeBeanReference((String) pointcut));
            parserContext.registerComponent(
                new AdvisorComponentDefinition(advisorBeanName, advisorDef));
        }
    }
    finally {
        this.parseState.pop();
    }
}
4.2.3.1 createAdvisorBeanDefinition

跟蹤標記4.2.3.1

此方法的實如今ConfigBeanDefinitionParser類中

// 4.2.3.1 建立一個顧問的 BeanDefinition
AbstractBeanDefinition advisorDef = createAdvisorBeanDefinition(advisorElement, parserContext);


/**
* Create a {@link RootBeanDefinition} for the advisor described in the supplied. Does <strong>not</strong>
* parse any associated '{@code pointcut}' or '{@code pointcut-ref}' attributes.
*
* 建立一個 advisor 的 RootBeanDefinition,不解析任何關聯的 pointcut 或 pointcut-ref 屬性
*/
private AbstractBeanDefinition createAdvisorBeanDefinition(Element advisorElement, ParserContext parserContext) {
    RootBeanDefinition advisorDefinition = new RootBeanDefinition(DefaultBeanFactoryPointcutAdvisor.class);
    advisorDefinition.setSource(parserContext.extractSource(advisorElement));

    // 拿到 advisor 標籤上的 advice-ref 屬性
    String adviceRef = advisorElement.getAttribute(ADVICE_REF);
    if (!StringUtils.hasText(adviceRef)) {
        parserContext.getReaderContext().error(
            "'advice-ref' attribute contains empty value.", advisorElement, this.parseState.snapshot());
    }
    else {
        
        // 添加到屬性鍵值對集合中
        advisorDefinition.getPropertyValues().add(
            ADVICE_BEAN_NAME, new RuntimeBeanNameReference(adviceRef));
    }

    // 拿到標籤上的 order 屬性
    if (advisorElement.hasAttribute(ORDER_PROPERTY)) {
        
        // 添加到屬性鍵值對集合中
        advisorDefinition.getPropertyValues().add(
            ORDER_PROPERTY, advisorElement.getAttribute(ORDER_PROPERTY));
    }

    return advisorDefinition;
}
4.2.3.2 parsePointcutProperty

跟蹤標記4.2.3.2

此方法的實如今ConfigBeanDefinitionParser類中

// 4.2.3.2 解析切入點屬性
Object pointcut = parsePointcutProperty(advisorElement, parserContext);


/**
* Parses the {@code pointcut} or {@code pointcut-ref} attributes of the supplied
* {@link Element} and add a {@code pointcut} property as appropriate. Generates a
* {@link org.springframework.beans.factory.config.BeanDefinition} for the pointcut if  necessary
* and returns its bean name, otherwise returns the bean name of the referred pointcut.
*
* 解析標籤上的 pointcut 屬性或者 pointcut-ref 屬性,並適當的添加 pointcut 屬性。
* 若是必要的話生成一個 pointcut 的 BeanDefinition,並返回 bean name,不然返回引用的 pointcut 的 bean name
*/
private Object parsePointcutProperty(Element element, ParserContext parserContext) {
    
    // pointcut 和 pointcut-ref 不能同時存在
    if (element.hasAttribute(POINTCUT) && element.hasAttribute(POINTCUT_REF)) {
        parserContext.getReaderContext().error(
            "Cannot define both 'pointcut' and 'pointcut-ref' on <advisor> tag.",
            element, this.parseState.snapshot());
        return null;
    }
    else if (element.hasAttribute(POINTCUT)) {
        
        // Create a pointcut for the anonymous pc and register it.
        // 爲匿名電腦建立一個切入點並註冊
        
        // 拿到標籤上的 pointcut 
        String expression = element.getAttribute(POINTCUT);
        
        // AspectJExpressionPointcut 做爲 bean class 建立一個 beanDefinition
        // beanDefinition 設置同步、原型,表達式添加到屬性鍵值對集合中
        AbstractBeanDefinition pointcutDefinition = createPointcutDefinition(expression);
        pointcutDefinition.setSource(parserContext.extractSource(element));
        return pointcutDefinition;
    }
    else if (element.hasAttribute(POINTCUT_REF)) {
        
        // 拿到標籤上的 pointcut-ref
        String pointcutRef = element.getAttribute(POINTCUT_REF);
        if (!StringUtils.hasText(pointcutRef)) {
            parserContext.getReaderContext().error(
                "'pointcut-ref' attribute contains empty value.", element, this.parseState.snapshot());
            return null;
        }
        
        // 直接返回字符串
        return pointcutRef;
    }
    else {
        parserContext.getReaderContext().error(
            "Must define one of 'pointcut' or 'pointcut-ref' on <advisor> tag.",
            element, this.parseState.snapshot());
        return null;
    }
}

4.2.4 parseAspect

跟蹤標記4.2.4

此方法的實如今ConfigBeanDefinitionParser類中

//4.2.4若是子標籤是aspect
parseAspect(elt, parserContext);

private void parseAspect(Element aspectElement, ParserContext parserContext) {
    
    // aspect 標籤上的兩屬性
    String aspectId = aspectElement.getAttribute(ID);
    String aspectName = aspectElement.getAttribute(REF);

    try {
        this.parseState.push(new AspectEntry(aspectId, aspectName));
        
        // 存放 BeanDefinition
        List<BeanDefinition> beanDefinitions = new ArrayList<BeanDefinition>();
        
        // 存放字符串的引用對象
        List<BeanReference> beanReferences = new ArrayList<BeanReference>();
        
        // aspect 標籤中有子標籤 declare-parents
        List<Element> declareParents = DomUtils.getChildElementsByTagName(aspectElement, DECLARE_PARENTS);
        for (int i = METHOD_INDEX; i < declareParents.size(); i++) {
            Element declareParentsElement = declareParents.get(i);
            beanDefinitions.add(parseDeclareParents(declareParentsElement, parserContext));
        }

        // We have to parse "advice" and all the advice kinds in one loop, to get the
        // ordering semantics right.
        // 爲了獲得正確順序,咱們不得不在一個循環中解析"通知"和全部通知類型
        
        // 拿到標籤下的子節點
        NodeList nodeList = aspectElement.getChildNodes();
        boolean adviceFoundAlready = false;
        for (int i = 0; i < nodeList.getLength(); i++) {
            Node node = nodeList.item(i);
            
            // 子節點是五種通知類型的狀況下:前置、後置、最終、異常、環繞通知
            if (isAdviceNode(node, parserContext)) {
                
                // 在解析第一個通知時才進入
                if (!adviceFoundAlready) {
                    adviceFoundAlready = true;
                    if (!StringUtils.hasText(aspectName)) {
                        parserContext.getReaderContext().error(
                            "<aspect> tag needs aspect bean reference via 'ref' attribute when declaring advices.",
                            aspectElement, this.parseState.snapshot());
                        return;
                    }
                    
                    // 將 aspect 標籤的 ref 屬性值(字符串)包裝後,添加到一個集合中
                    beanReferences.add(new RuntimeBeanReference(aspectName));
                }
                
                // 4.2.4.1 解析通知
                AbstractBeanDefinition advisorDefinition = parseAdvice(
                    aspectName, i, aspectElement, (Element) node, parserContext, beanDefinitions, beanReferences);
                
                // 返回的 Bean Definition 添加到另外一個集合中
                beanDefinitions.add(advisorDefinition);
            }
        }

        // new 一個 AspectComponentDefinition
        AspectComponentDefinition aspectComponentDefinition = createAspectComponentDefinition(
            aspectElement, aspectId, beanDefinitions, beanReferences, parserContext);
        
        parserContext.pushContainingComponent(aspectComponentDefinition);

        // 若是aspect標籤下還有pointcut子標籤,調用4.2.2方法進行解析
        List<Element> pointcuts = DomUtils.getChildElementsByTagName(aspectElement, POINTCUT);
        for (Element pointcutElement : pointcuts) {
            parsePointcut(pointcutElement, parserContext);
        }

        // 將新建立的 AspectComponentDefinition 註冊到組合組件定義器中
        parserContext.popAndRegisterContainingComponent();
    }
    finally {
        this.parseState.pop();
    }
}
4.2.4.1 parseAdvice

跟蹤標記4.2.4.1

此方法的實如今ConfigBeanDefinitionParser類中

// 4.2.4.1 解析通知
AbstractBeanDefinition advisorDefinition = parseAdvice(
    aspectName, i, aspectElement, (Element) node, parserContext, beanDefinitions, beanReferences);


/**
* Parses one of '{@code before}', '{@code after}', '{@code after-returning}',
* '{@code after-throwing}' or '{@code around}' and registers the resulting
* BeanDefinition with the supplied BeanDefinitionRegistry.
* 
* 解析五個通知標籤中的一個,而且註冊最終的 BeanDefinition 到工廠中
*/
private AbstractBeanDefinition parseAdvice(
    String aspectName, int order, Element aspectElement, Element adviceElement, ParserContext parserContext,
    List<BeanDefinition> beanDefinitions, List<BeanReference> beanReferences) {

    try {
        this.parseState.push(new AdviceEntry(parserContext.getDelegate().getLocalName(adviceElement)));

        // create the method factory bean
        // 建立一個 method factory bean 的 RootBeanDefinition
        RootBeanDefinition methodDefinition = new RootBeanDefinition(MethodLocatingFactoryBean.class);
        methodDefinition.getPropertyValues().add("targetBeanName", aspectName);
        methodDefinition.getPropertyValues().add("methodName", adviceElement.getAttribute("method"));
        methodDefinition.setSynthetic(true);

        // create instance factory definition
        // 建立一個 instance factory definition 的 RootBeanDefinition
        RootBeanDefinition aspectFactoryDef =
            new RootBeanDefinition(SimpleBeanFactoryAwareAspectInstanceFactory.class);
        aspectFactoryDef.getPropertyValues().add("aspectBeanName", aspectName);
        aspectFactoryDef.setSynthetic(true);

        // register the pointcut
        // 註冊 pointcut ,進入這個方法
        AbstractBeanDefinition adviceDef = createAdviceDefinition(
            adviceElement, parserContext, aspectName, order, methodDefinition, aspectFactoryDef,
            beanDefinitions, beanReferences);

        // configure the advisor
        // 配置顧問
        
        // 建立一個顧問的 RootBeanDefinition
        RootBeanDefinition advisorDefinition = new RootBeanDefinition(AspectJPointcutAdvisor.class);
        
        advisorDefinition.setSource(parserContext.extractSource(adviceElement));
        
        // 將前面獲得的通知的 BeanDefinition 添加到顧問的 constructorArgumentValues 中
        advisorDefinition.getConstructorArgumentValues().addGenericArgumentValue(adviceDef);
        
        // 是否有優先級屬性在 aspect 標籤上,添加進屬性鍵值對集合中
        if (aspectElement.hasAttribute(ORDER_PROPERTY)) {
            advisorDefinition.getPropertyValues().add(
                ORDER_PROPERTY, aspectElement.getAttribute(ORDER_PROPERTY));
        }

        // register the final advisor
        // 註冊最終顧問的 RootBeanDefinition
        parserContext.getReaderContext().registerWithGeneratedName(advisorDefinition);

        return advisorDefinition;
    }
    finally {
        this.parseState.pop();
    }
}


/**
* Creates the RootBeanDefinition for a POJO advice bean. Also causes pointcut
* parsing to occur so that the pointcut may be associate with the advice bean.
* This same pointcut is also configured as the pointcut for the enclosing
* Advisor definition using the supplied MutablePropertyValues.
*
* 建立一個 POJO 通知 bean 的 RootBeanDefinition 。這使得切入點被解析,並和通知 bean 產生了關聯。
* 相同的切入點也會被封閉的顧問定義配置爲切入點。顧問使用提供的 MutablePropertyValues
*/
private AbstractBeanDefinition createAdviceDefinition(
    Element adviceElement, ParserContext parserContext, String aspectName, int order,
    RootBeanDefinition methodDef, RootBeanDefinition aspectFactoryDef,
    List<BeanDefinition> beanDefinitions, List<BeanReference> beanReferences) {

    // 根據不一樣的通知類型設置 beanClass,建立 RootBeanDefinition
    RootBeanDefinition adviceDefinition = new RootBeanDefinition(getAdviceClass(adviceElement, parserContext));
    adviceDefinition.setSource(parserContext.extractSource(adviceElement));

    adviceDefinition.getPropertyValues().add(ASPECT_NAME_PROPERTY, aspectName);
    
    // 這個 order 是子標籤(通知標籤)被遍歷時,所處集合的位置
    adviceDefinition.getPropertyValues().add(DECLARATION_ORDER_PROPERTY, order);

    // returning 屬性
    if (adviceElement.hasAttribute(RETURNING)) {
        adviceDefinition.getPropertyValues().add(
            RETURNING_PROPERTY, adviceElement.getAttribute(RETURNING));
    }
    
    // throwing 屬性
    if (adviceElement.hasAttribute(THROWING)) {
        adviceDefinition.getPropertyValues().add(
            THROWING_PROPERTY, adviceElement.getAttribute(THROWING));
    }
    
    // arg-names 屬性
    if (adviceElement.hasAttribute(ARG_NAMES)) {
        adviceDefinition.getPropertyValues().add(
            ARG_NAMES_PROPERTY, adviceElement.getAttribute(ARG_NAMES));
    }

    ConstructorArgumentValues cav = adviceDefinition.getConstructorArgumentValues();
    
    // 添加上一層方法建立的 RootBeanDefinition
    cav.addIndexedArgumentValue(METHOD_INDEX, methodDef);

    // 若是是切入點的引用,直接返回字符串,不然建立一個 RootBeanDefinition ,設置表達式等屬性並返回
    Object pointcut = parsePointcutProperty(adviceElement, parserContext
                                            
    // 添加解析了切入點屬性後的返回值
    if (pointcut instanceof BeanDefinition) {
        cav.addIndexedArgumentValue(POINTCUT_INDEX, pointcut);
        
        // Bean Definition 的狀況添加到一個集合
        beanDefinitions.add((BeanDefinition) pointcut);
    }
    else if (pointcut instanceof String) {
        RuntimeBeanReference pointcutRef = new RuntimeBeanReference((String) pointcut);
        cav.addIndexedArgumentValue(POINTCUT_INDEX, pointcutRef);
        
        // 字符串的狀況添加到另一個集合
        beanReferences.add(pointcutRef);
    }

    // 添加上一層方法建立的 RootBeanDefinition
    cav.addIndexedArgumentValue(ASPECT_INSTANCE_FACTORY_INDEX, aspectFactoryDef);

    return adviceDefinition;
}

4.2.5 popAndRegisterContainingComponent

跟蹤標記4.2.5

此方法的實如今ParserContext類中

//4.2.5彈出組件
parserContext.popAndRegisterContainingComponent();

public void popAndRegisterContainingComponent() {
    registerComponent(popContainingComponent());
}

public CompositeComponentDefinition popContainingComponent() {
    
    //先將ParserContext類containingComponents屬性的組件彈出
    //好比aop:config,這個組件中包含着多個子標籤對應的嵌套組件
    return (CompositeComponentDefinition) this.containingComponents.pop();
}

//拿到彈出的組件進行註冊
public void registerComponent(ComponentDefinition component) {
    
    //再拿到parserContext中的containingComponents屬性中,最後一個組件
    //可是這裏前面已經彈出,這裏已經沒有,因此返回null
    CompositeComponentDefinition containingComponent = getContainingComponent();
    if (containingComponent != null) {
        containingComponent.addNestedComponent(component);
    }
    else {
        
        //沒作具體的實現
        this.readerContext.fireComponentRegistered(component);
    }
}

到這裏整個loadBeanDefinitions方法跟蹤完成。

有興趣的能夠看下,spring配置文件中,組件掃描標籤 的解析過程:
https://www.jianshu.com/p/e764a6959eeb

總結

4

  • 走解析自定義元素的方法。先拿到元素的名稱空間URI,經過URI拿到對應的處理器,處理器中一般註冊了許多解析器,每一個解析器對應着該名稱空間下的一個標籤。
  • 4.2 利用解析器解析對應的元素標籤

——————————————————————————————————

  • 4.2
  • 對於<aop:config>標籤來講,其對應的解析器爲 ConfigBeanDefinitionParser
  • 先建立一個組合組件定義器,標籤名放入其中
  • 4.2.1 若是必要的話註冊一個自動代理建立器
  • 4.2.2 而後拿到標籤下的子標籤,一共三種:pointcutadvisoraspect,根據不一樣標籤走不一樣方法

——————————————————————————————————

  • 4.2.1
  • 工廠中已經註冊了建立器,則根據其 BeanDefinition 中 beanClassName 的優先級和入參Class對象的優先級對比進行選擇,入參Class對象優先級高則設置爲 BeanDefinition 新的 beanClassName ;工廠中若是沒有註冊建立器,則建立 RootBeanDefinition,並在工廠中註冊建立器。
  • 若是<aop:config>標籤上有配置屬性proxy-target-class或者expose-proxy等,則將其添加到 BeanDefinition 的屬性鍵值對集合中。
  • 若是建立器是新建立的,則註冊建立器到parserContext中,其實就是將建立器的 BeanDefinition 添加到組合組件定義器中

——————————————————————————————————

  • 4.2.2
  • 標籤pointcut方法:建立 bean definition,指定 beanClass,默認多例,同步,將切入點表達式expression添加到bean definition的propertyValues中;將 bean definition 註冊到工廠;包裹 bean definition 註冊到組合組件定義器中。
  • 標籤advisor方法:建立 bean definition,指定 beanClass,以adviceBeanName爲key,將標籤上屬性advice-ref的值以 RuntimeBeanNameReference 類包裝後,添加到 BeanDefinition 的屬性鍵值對集合中;而後註冊 bean definition; 解析pointcut-ref或者pointcut屬性,添加到 BeanDefinition 的屬性鍵值對集合中;包裹 bean definition 註冊到組合組件定義器中。
  • 標籤aspect方法

——————————————————————————————————

  • 標籤aspect方法
  • 拿到aspect標籤上屬性 id、ref 的值,建兩集合,一個放 BeanDefinition ,一個放字符串的引用對象。
  • 遍歷子標籤,在掃描到第一個子標籤時用 RuntimeBeanReference 類包裝 ref 字符串,也就是 aspectName,並將包裝類放入到存放字符串引用的集合中。
  • 4.2.4.1 遍歷時解析通知,將返回的 BeanDefinition 存放到另外一個集合中
  • 利用 id、兩集合新建一個 AspectComponentDefinition
  • 若是aspect標籤下還有pointcut子標籤,調用標籤pointcut方法進行解析
  • 將新建立的 AspectComponentDefinition 註冊到組合組件定義器中。

——————————————————————————————————

  • 4.2.4.1
  • 建立 RootBeanDefinition (methodDefinition),設置MethodLocatingFactoryBean.class爲 beanClass、設置爲同步、將標籤aspect上的 ref 屬性值和通知標籤(例如:aop:before)上的 method 屬性值添加到 methodDefinition 的屬性鍵值對集合中
  • 建立 RootBeanDefinition (aspectFactoryDef),設置SimpleBeanFactoryAwareAspectInstanceFactory.class爲 beanClass、設置爲同步、將標籤aspect上的 ref 屬性值添加到 aspectFactoryDef 的屬性鍵值對集合中
  • 建立 RootBeanDefinition (adviceDefinition),根據不一樣的通知類型設置 beanClass,將 ref 屬性值、子標籤遍歷時所處的集合位置、子標籤(通知標籤)上的屬性值添加到 adviceDefinition的屬性鍵值對集合中;
  • 解析通知標籤上 pointcut 或 pointcut-ref 屬性,返回 BeanDefinition 或者字符串,根據返回值不一樣放入到不一樣的集合中;拿到 adviceDefinition 的 constructorArgumentValues 屬性,依次添加 methodDefinition、BeanDefinition / 字符串、aspectFactoryDef 到 constructorArgumentValues 中;
  • 建立 RootBeanDefinition (advisorDefinition),設置AspectJPointcutAdvisor.class爲 beanClass,拿到 advisorDefinition 的 constructorArgumentValues 屬性,添加 adviceDefinition
  • 註冊 advisorDefinition 到工廠中,並返回 advisorDefinition
相關文章
相關標籤/搜索