由於字數超過了限制,因此分紅了三篇,承接上篇:
https://www.jianshu.com/p/46e27afd7d96java
代碼過寬,能夠shift + 鼠標滾輪 左右滑動查看node
<!-- 事務處理,事務只針對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)); }
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的方法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的方法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的方法
該方法在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
此方法的實如今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
此方法的實如今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
此方法的實如今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
此方法的實如今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
此方法的實如今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
此方法的實如今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
此方法的實如今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
此方法的實如今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
此方法的實如今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
——————————————————————————————————
<aop:config>
標籤來講,其對應的解析器爲 ConfigBeanDefinitionParserpointcut
、advisor
、aspect
,根據不一樣標籤走不一樣方法——————————————————————————————————
<aop:config>
標籤上有配置屬性proxy-target-class
或者expose-proxy
等,則將其添加到 BeanDefinition 的屬性鍵值對集合中。parserContext
中,其實就是將建立器的 BeanDefinition 添加到組合組件定義器中——————————————————————————————————
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 ,一個放字符串的引用對象。aspect
標籤下還有pointcut
子標籤,調用標籤pointcut
方法進行解析——————————————————————————————————
MethodLocatingFactoryBean.class
爲 beanClass、設置爲同步、將標籤aspect
上的 ref 屬性值和通知標籤(例如:aop:before
)上的 method 屬性值添加到 methodDefinition 的屬性鍵值對集合中SimpleBeanFactoryAwareAspectInstanceFactory.class
爲 beanClass、設置爲同步、將標籤aspect
上的 ref 屬性值添加到 aspectFactoryDef 的屬性鍵值對集合中AspectJPointcutAdvisor.class
爲 beanClass,拿到 advisorDefinition 的 constructorArgumentValues 屬性,添加 adviceDefinition