spring解析配置文件(三)


一、從XmlBeanDefinitionReader的registerBeanDefinitions(doc,resource)開始

1 protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
2             throws BeanDefinitionStoreException {
3         try {
4             Document doc = doLoadDocument(inputSource, resource);
5             return registerBeanDefinitions(doc, resource);
6         }

進入第5行的registerBeanDefinitions方法

1 public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
2         BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
3         int countBefore = getRegistry().getBeanDefinitionCount();
4         documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
5         return getRegistry().getBeanDefinitionCount() - countBefore;
6     }

第二行創建了一個bean定義文檔閱讀器,創建的代碼如下,第三行的getRegistry()方法得到是DefaultListableBeanFactory類的實例,是個bean工廠,這個工廠在准備讀取xml時創建xml閱讀器的時候就已經設置進去,getBeanDefinitions方法里的代碼就這一句this.beanDefinitionMap.size(),獲取bean定義容器的大小,很顯然對於我這里是沒有的,因為還沒解析xml。

1 protected BeanDefinitionDocumentReader createBeanDefinitionDocumentReader() {
2         return BeanDefinitionDocumentReader.class.cast(BeanUtils.instantiateClass(this.documentReaderClass));
3     }

在看看第4行的documentReader.registerBeanDefinitions這個方法

1 @Override
2     public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
3         this.readerContext = readerContext;
4         logger.debug("Loading bean definitions");
5         Element root = doc.getDocumentElement();
6         doRegisterBeanDefinitions(root);
7     }

第5行獲得了xml的根元素<beans>然后調用

doRegisterBeanDefinitions方法,並把根元素傳入進入

 1 protected void doRegisterBeanDefinitions(Element root) {
 2         // Any nested <beans> elements will cause recursion in this method. In
 3         // order to propagate and preserve <beans> default-* attributes correctly,
 4         // keep track of the current (parent) delegate, which may be null. Create
 5         // the new (child) delegate with a reference to the parent for fallback purposes,
 6         // then ultimately reset this.delegate back to its original (parent) reference.
 7         // this behavior emulates a stack of delegates without actually necessitating one.
 8         BeanDefinitionParserDelegate parent = this.delegate;
 9         this.delegate = createDelegate(getReaderContext(), root, parent);
10 
11         if (this.delegate.isDefaultNamespace(root)) {
12             String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
13             if (StringUtils.hasText(profileSpec)) {
14                 String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
15                         profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
16                 if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
17                     return;
18                 }
19             }
20         }
21 
22         preProcessXml(root);
23         parseBeanDefinitions(root, this.delegate);
24  postProcessXml(root);
25 
26         this.delegate = parent;
27     }
第9行創建了使用createDelegate方法創建了一個BeanDefinitionParserDelegate類的實例,它內部的代碼如下
1 protected BeanDefinitionParserDelegate createDelegate(
2             XmlReaderContext readerContext, Element root, BeanDefinitionParserDelegate parentDelegate) {
3 
4         BeanDefinitionParserDelegate delegate = new BeanDefinitionParserDelegate(readerContext);
5         delegate.initDefaults(root, parentDelegate);
6         return delegate;
7     }

第4行的readerContext是一個XMLReaderContext,繼續往下調用了initDefaults方法,初始化默認值

1 public void initDefaults(Element root, BeanDefinitionParserDelegate parent) {
2         populateDefaults(this.defaults, (parent != null ? parent.defaults : null), root);
3         this.readerContext.fireDefaultsRegistered(this.defaults);
4     }

進入populateDefaults方法

 1 protected void populateDefaults(DocumentDefaultsDefinition defaults, DocumentDefaultsDefinition parentDefaults, Element root) {
 2         String lazyInit = root.getAttribute(DEFAULT_LAZY_INIT_ATTRIBUTE);
 3         if (DEFAULT_VALUE.equals(lazyInit)) {
 4             // Potentially inherited from outer <beans> sections, otherwise falling back to false.
 5             lazyInit = (parentDefaults != null ? parentDefaults.getLazyInit() : FALSE_VALUE);
 6         }
 7         defaults.setLazyInit(lazyInit);
 8 
 9         String merge = root.getAttribute(DEFAULT_MERGE_ATTRIBUTE);
10         if (DEFAULT_VALUE.equals(merge)) {
11             // Potentially inherited from outer <beans> sections, otherwise falling back to false.
12             merge = (parentDefaults != null ? parentDefaults.getMerge() : FALSE_VALUE);
13         }
14         defaults.setMerge(merge);
15 
16         String autowire = root.getAttribute(DEFAULT_AUTOWIRE_ATTRIBUTE);
17         if (DEFAULT_VALUE.equals(autowire)) {
18             // Potentially inherited from outer <beans> sections, otherwise falling back to 'no'.
19             autowire = (parentDefaults != null ? parentDefaults.getAutowire() : AUTOWIRE_NO_VALUE);
20         }
21         defaults.setAutowire(autowire);
22 
23         // Don't fall back to parentDefaults for dependency-check as it's no longer supported in
24         // <beans> as of 3.0. Therefore, no nested <beans> would ever need to fall back to it.
25         defaults.setDependencyCheck(root.getAttribute(DEFAULT_DEPENDENCY_CHECK_ATTRIBUTE));
26 
27         if (root.hasAttribute(DEFAULT_AUTOWIRE_CANDIDATES_ATTRIBUTE)) {
28             defaults.setAutowireCandidates(root.getAttribute(DEFAULT_AUTOWIRE_CANDIDATES_ATTRIBUTE));
29         }
30         else if (parentDefaults != null) {
31             defaults.setAutowireCandidates(parentDefaults.getAutowireCandidates());
32         }
33 
34         if (root.hasAttribute(DEFAULT_INIT_METHOD_ATTRIBUTE)) {
35             defaults.setInitMethod(root.getAttribute(DEFAULT_INIT_METHOD_ATTRIBUTE));
36         }
37         else if (parentDefaults != null) {
38             defaults.setInitMethod(parentDefaults.getInitMethod());
39         }
40 
41         if (root.hasAttribute(DEFAULT_DESTROY_METHOD_ATTRIBUTE)) {
42             defaults.setDestroyMethod(root.getAttribute(DEFAULT_DESTROY_METHOD_ATTRIBUTE));
43         }
44         else if (parentDefaults != null) {
45             defaults.setDestroyMethod(parentDefaults.getDestroyMethod());
46         }
47 
48         defaults.setSource(this.readerContext.extractSource(root));
49     }

第2行的DEFAULT_LAZY_INIT_ATTRIBUTE的值是default-lazy-init,第7行設置懶加載,還有默認的初始化方法什么的,把這些個屬性全都設置到

DocumentDefaultsDefinition 中。這個方法返回后繼續調用了XmlReaderContext的fireDefaultsRegistered方法,不過里面啥都沒做。

接下來有回到了
doRegisterBeanDefinitions方法
 1 protected void doRegisterBeanDefinitions(Element root) {
 2         // Any nested <beans> elements will cause recursion in this method. In
 3         // order to propagate and preserve <beans> default-* attributes correctly,
 4         // keep track of the current (parent) delegate, which may be null. Create
 5         // the new (child) delegate with a reference to the parent for fallback purposes,
 6         // then ultimately reset this.delegate back to its original (parent) reference.
 7         // this behavior emulates a stack of delegates without actually necessitating one.
 8         BeanDefinitionParserDelegate parent = this.delegate;
 9         this.delegate = createDelegate(getReaderContext(), root, parent);
10 
11         if (this.delegate.isDefaultNamespace(root)) {
12             String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
13             if (StringUtils.hasText(profileSpec)) {
14                 String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
15                         profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
16                 if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
17                     return;
18                 }
19             }
20         }
21 
22         preProcessXml(root);
23         parseBeanDefinitions(root, this.delegate);
24         postProcessXml(root);
25 
26         this.delegate = parent;
27     }

第11行判斷當前的根元素是否是默認的命名空間,spring中存在着兩種標簽,一種是默認的標簽,另一種是自定義標簽

第12行獲得profile屬性,這個屬性應用於對個beans標簽的情況,從spring3開始的,這樣我們可以寫多套bean定義,特別是使用到數據源的時候,可以切換不同的數據源,想要使用哪個bean定義就激活誰,想詳細了解的,可以去查查資料。

第22行是個空方法,里面什么也沒做,這個地方可以進行擴展,在解析bean定義之前,可以先處理自定義的標簽

第23行方法的代碼如下

 1 protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
 2         if (delegate.isDefaultNamespace(root)) {
 3             NodeList nl = root.getChildNodes();
 4             for (int i = 0; i < nl.getLength(); i++) {
 5                 Node node = nl.item(i);
 6                 if (node instanceof Element) {
 7                     Element ele = (Element) node;
 8                     if (delegate.isDefaultNamespace(ele)) {
 9  parseDefaultElement(ele, delegate);
10                     }
11                     else {
12                         delegate.parseCustomElement(ele);
13                     }
14                 }
15             }
16         }
17         else {
18             delegate.parseCustomElement(root);
19         }
20     }

第2行判斷root是否是默認的命名空間,第3行獲得根元素下的子節點,循環遍歷子節點,第8行判斷每個子節點是否是默認的命名空間,如果是就執行parseDefaultElement方法,否則

執行parseCustomElement方法,什么是自定義的標簽呢,比如用戶自己實現的標簽,還有就是spring的aop,tx這類標簽都是有自定義的命名空間的標簽

我們進到parseCustomElement方法中看看

1 public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {
2         String namespaceUri = getNamespaceURI(ele);
3         NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
4         if (handler == null) {
5             error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
6             return null;
7         }
8         return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
9     }

第2行獲取這個元素的命名空間,通過命名空間可以在類路徑下的spring.handlers中找到對應的處理器,在spring.schemas中找到對應的xsd文件。進入resolve方法查看一下他的

代碼邏輯

 1 @Override
 2     public NamespaceHandler resolve(String namespaceUri) {
 3         Map<String, Object> handlerMappings = getHandlerMappings();
 4         Object handlerOrClassName = handlerMappings.get(namespaceUri);
 5         if (handlerOrClassName == null) {
 6             return null;
 7         }
 8         else if (handlerOrClassName instanceof NamespaceHandler) {
 9             return (NamespaceHandler) handlerOrClassName;
10         }
11         else {
12             String className = (String) handlerOrClassName;
13             try {
14                 Class<?> handlerClass = ClassUtils.forName(className, this.classLoader);
15                 if (!NamespaceHandler.class.isAssignableFrom(handlerClass)) {
16                     throw new FatalBeanException("Class [" + className + "] for namespace [" + namespaceUri +
17                             "] does not implement the [" + NamespaceHandler.class.getName() + "] interface");
18                 }
19                 NamespaceHandler namespaceHandler = (NamespaceHandler) BeanUtils.instantiateClass(handlerClass);
20                 namespaceHandler.init();
21                 handlerMappings.put(namespaceUri, namespaceHandler);
22                 return namespaceHandler;
23             }
24             catch (ClassNotFoundException ex) {
25                 throw new FatalBeanException("NamespaceHandler class [" + className + "] for namespace [" +
26                         namespaceUri + "] not found", ex);
27             }
28             catch (LinkageError err) {
29                 throw new FatalBeanException("Invalid NamespaceHandler class [" + className + "] for namespace [" +
30                         namespaceUri + "]: problem with handler class file or dependent class", err);
31             }
32         }
33     }

第3行代碼getHandlerMappings()獲得所有的命名空間和處理程序的映射

 1 private Map<String, Object> getHandlerMappings() {
 2         if (this.handlerMappings == null) {
 3             synchronized (this) {
 4                 if (this.handlerMappings == null) {
 5                     try {
 6                         Properties mappings =
 7                                 PropertiesLoaderUtils.loadAllProperties(this.handlerMappingsLocation, this.classLoader);
 8                         if (logger.isDebugEnabled()) {
 9                             logger.debug("Loaded NamespaceHandler mappings: " + mappings);
10                         }
11                         Map<String, Object> handlerMappings = new ConcurrentHashMap<String, Object>(mappings.size());
12                         CollectionUtils.mergePropertiesIntoMap(mappings, handlerMappings);
13                         this.handlerMappings = handlerMappings;
14                     }
15                     catch (IOException ex) {
16                         throw new IllegalStateException(
17                                 "Unable to load NamespaceHandler mappings from location [" + this.handlerMappingsLocation + "]", ex);
18                     }
19                 }
20             }
21         }
22         return this.handlerMappings;
23     }

進入第7行看看

 1 public static Properties loadAllProperties(String resourceName, ClassLoader classLoader) throws IOException {
 2         Assert.notNull(resourceName, "Resource name must not be null");
 3         ClassLoader classLoaderToUse = classLoader;
 4         if (classLoaderToUse == null) {
 5             classLoaderToUse = ClassUtils.getDefaultClassLoader();
 6         }
 7         Enumeration<URL> urls = (classLoaderToUse != null ? classLoaderToUse.getResources(resourceName) :
 8                 ClassLoader.getSystemResources(resourceName));
 9         Properties props = new Properties();
10         while (urls.hasMoreElements()) {
11             URL url = urls.nextElement();
12             URLConnection con = url.openConnection();
13             ResourceUtils.useCachesIfNecessary(con);
14             InputStream is = con.getInputStream();
15             try {
16                 if (resourceName.endsWith(XML_FILE_EXTENSION)) {
17                     props.loadFromXML(is);
18                 }
19                 else {
20                     props.load(is);
21                 }
22             }
23             finally {
24                 is.close();
25             }
26         }
27         return props;
28     }

它是通過加載器加載classpath下的META-INF/spring.handler文件,使用jdk的Properties方法加載,加載完后返回properties的實例,最后拿到對應的標簽處理器

 

 拿到命名空間處理器的類名后

1 NamespaceHandler namespaceHandler = (NamespaceHandler) BeanUtils.instantiateClass(handlerClass);
2                 namespaceHandler.init();
3                 handlerMappings.put(namespaceUri, namespaceHandler);
4                 return namespaceHandler;

第1行使用bean助手類實例化了這個命名空間處理器,並進行了初始化,加入我顯示使用的是aop的命名空間,那么這個命名空間處理器是AopNamespaceHandler類的實例

它對應init方法代碼如下:這個aop命名空間處理器中擁有下面這些類別的標簽解析器,第一個我們是最屬性的,這個解析器里提供了aop:config標簽中pointcut,before之類的解析方法

第3行將初始化好的命名空間處理器放到handlerMappings中,如果下次要使用就直接可以拿到,不需要在此實例化

@Override
    public void init() {
        // 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());
    }

下面是一些bean定義解析器的繼承結構,各種各樣的解析器

 

向處理器中注冊解析器
1 protected final void registerBeanDefinitionParser(String elementName, BeanDefinitionParser parser) {
2         this.parsers.put(elementName, parser);
3     }

第2行的parsers是一個Map,用來存放bean定義解析器

得到命名空間處理器后再調用命名空間處理器的parse方法handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));

進入parse方法,這個方法又調用了findParserForElement方法
1 private BeanDefinitionParser findParserForElement(Element element, ParserContext parserContext) {
      
2 String localName = parserContext.getDelegate().getLocalName(element); 3 BeanDefinitionParser parser = this.parsers.get(localName); 4 if (parser == null) { 5 parserContext.getReaderContext().fatal( 6 "Cannot locate BeanDefinitionParser for element [" + localName + "]", element); 7 } 8 return parser; 9 }

第2行,通過這個元素拿到了它的本地名字,比如aop:config元素的本地名為config

通過config從命名空間中的解析器map容器中拿到了對應的解析器,然后調用這個aop的config解析器的parse方法

 1 @Override
 2     public BeanDefinition parse(Element element, ParserContext parserContext) {
 3         CompositeComponentDefinition compositeDef =
 4                 new CompositeComponentDefinition(element.getTagName(), parserContext.extractSource(element));
 5         parserContext.pushContainingComponent(compositeDef);
 6 
 7         configureAutoProxyCreator(parserContext, element);
 8 
 9         List<Element> childElts = DomUtils.getChildElements(element);
10         for (Element elt: childElts) {
11             String localName = parserContext.getDelegate().getLocalName(elt);
12             if (POINTCUT.equals(localName)) {
13                 parsePointcut(elt, parserContext);
14             }
15             else if (ADVISOR.equals(localName)) {
16                 parseAdvisor(elt, parserContext);
17             }
18             else if (ASPECT.equals(localName)) {
19                 parseAspect(elt, parserContext);
20             }
21         }
22 
23         parserContext.popAndRegisterContainingComponent();
24         return null;
25     }

 

第三行創建了一個組件定義,並將它壓入ParseContext上下文中的stack中

進入第7行的方法
1 private void configureAutoProxyCreator(ParserContext parserContext, Element element) {
2         AopNamespaceUtils.registerAspectJAutoProxyCreatorIfNecessary(parserContext, element);
3     }

這個方法是在配置自動代理創建者,這個方法在配置了<aop:config>才使用,如果你配置的是<aop:aspect-autoproxy/>這個標簽,就會使用AspectJAutoProxyBeanDefinitionParser這個類的解析器。回到aop:config這個標簽的解析器,上面的第2行使用了AopNamespaceUtils aop命名空間助手類注冊一個自動代理切面創建者,進入這個方法看看

1 public static void registerAspectJAutoProxyCreatorIfNecessary(
2             ParserContext parserContext, Element sourceElement) {
3 
4         BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAutoProxyCreatorIfNecessary(
5                 parserContext.getRegistry(), parserContext.extractSource(sourceElement));
6         useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
7         registerComponentIfNecessary(beanDefinition, parserContext);
8     }

 

第4行調用了registerAspectJAutoProxyCreatorIfNecessary的重載方法,這個方法傳入了BeanRegistry類的對象(這里的這個實例實際上是DefaultListableBeanFactory)和ParseContext包裝后的可提取資源實例
進入這個方法查看一下它的代碼
1 public static BeanDefinition registerAspectJAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, Object source) {
2         return registerOrEscalateApcAsRequired(AspectJAwareAdvisorAutoProxyCreator.class, registry, source);
3     }

第2行傳入了一個AspectJAwareAdvisorAutoProxyCreator.class類對象,暫且不管它是干啥的,繼續往下看

 1 private static BeanDefinition registerOrEscalateApcAsRequired(Class<?> cls, BeanDefinitionRegistry registry, Object source) {
 2         Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
 3         if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
 4             BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
 5             if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
 6                 int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
 7                 int requiredPriority = findPriorityForClass(cls);
 8                 if (currentPriority < requiredPriority) {
 9                     apcDefinition.setBeanClassName(cls.getName());
10                 }
11             }
12             return null;
13         }
14         RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
15         beanDefinition.setSource(source);
16         beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
17         beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
18         registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
19         return beanDefinition;
20     }

第3行判斷這個BeanFactory中的BeanDefinitionMap容器中是否存在一個key叫做AUTO_PROXY_CREATOR_BEAN_NAME

(org.springframework.aop.config.internalAutoProxyCreator)的元素,如果存在就獲得他的BeanDefinition對象,並且與我們傳進來的AspectJAwareAdvisorAutoProxyCreator

類名是否一樣,如果一樣就要根據優先級來選擇其中一個作為自動創建代理類,在AopConfigUtils類中有個靜態的屬性list集合APC_PRIORITY_LIST,

它在靜態塊中初始化

 1 private static final List<Class<?>> APC_PRIORITY_LIST = new ArrayList<Class<?>>();
 2 
 3     /**
 4      * Setup the escalation list.
 5      */
 6     static {
 7         APC_PRIORITY_LIST.add(InfrastructureAdvisorAutoProxyCreator.class);
 8         APC_PRIORITY_LIST.add(AspectJAwareAdvisorAutoProxyCreator.class);
 9         APC_PRIORITY_LIST.add(AnnotationAwareAspectJAutoProxyCreator.class);
10     }

我們在看看findPriorityForClass()方法

private static int findPriorityForClass(String className) {
        for (int i = 0; i < APC_PRIORITY_LIST.size(); i++) {
            Class<?> clazz = APC_PRIORITY_LIST.get(i);
            if (clazz.getName().equals(className)) {
                return i;
            }
        }
        throw new IllegalArgumentException(
                "Class name [" + className + "] is not a known auto-proxy creator class");
    }

}

看見了,它是以這些定義的順序進行決定優先級的,只不過在集合中越后,優先級就越高

讓我們再次返回到registerOrEscalateApcAsRequired這個方法

 1 private static BeanDefinition registerOrEscalateApcAsRequired(Class<?> cls, BeanDefinitionRegistry registry, Object source) {
 2         Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
 3         if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
 4             BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
 5             if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
 6                 int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
 7                 int requiredPriority = findPriorityForClass(cls);
 8                 if (currentPriority < requiredPriority) {
 9                     apcDefinition.setBeanClassName(cls.getName());
10                 }
11             }
12             return null;
13         }
14         RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
15         beanDefinition.setSource(source);
16         beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
17         beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
18         registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
19         return beanDefinition;
20     }

如果容器中沒有AUTO_PROXY_CREATOR_BEAN_NAME對應的自動代理器,那么就跳到第14行,創建一個AspectJAwareAdvisorAutoProxyCreator實例注入到RootBeanDefinition類中,這個類是BeanDefinition的子類,第16行設置了這個BeanDefinition的優先級,第17行設置這個BeanDefinition的角色定位,用戶自己定義的bean的角色是BeanDefinition.ROLE_APPLICTION

 第18行向beanFactory中注冊這個BeanDefinition,它的實現代碼如下

 1 @Override
 2     public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
 3             throws BeanDefinitionStoreException {
 4 
 5         Assert.hasText(beanName, "Bean name must not be empty");
 6         Assert.notNull(beanDefinition, "BeanDefinition must not be null");
 7 
 8         if (beanDefinition instanceof AbstractBeanDefinition) {
 9             try {
10                 ((AbstractBeanDefinition) beanDefinition).validate();
11             }
12             catch (BeanDefinitionValidationException ex) {
13                 throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
14                         "Validation of bean definition failed", ex);
15             }
16         }
17 
18         BeanDefinition oldBeanDefinition;
19 
20         oldBeanDefinition = this.beanDefinitionMap.get(beanName);
21         if (oldBeanDefinition != null) {
22             if (!isAllowBeanDefinitionOverriding()) {
23                 throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
24                         "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
25                         "': There is already [" + oldBeanDefinition + "] bound.");
26             }
27             else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) {
28                 // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
29                 if (this.logger.isWarnEnabled()) {
30                     this.logger.warn("Overriding user-defined bean definition for bean '" + beanName +
31                             "' with a framework-generated bean definition: replacing [" +
32                             oldBeanDefinition + "] with [" + beanDefinition + "]");
33                 }
34             }
35             else if (!beanDefinition.equals(oldBeanDefinition)) {
36                 if (this.logger.isInfoEnabled()) {
37                     this.logger.info("Overriding bean definition for bean '" + beanName +
38                             "' with a different definition: replacing [" + oldBeanDefinition +
39                             "] with [" + beanDefinition + "]");
40                 }
41             }
42             else {
43                 if (this.logger.isDebugEnabled()) {
44                     this.logger.debug("Overriding bean definition for bean '" + beanName +
45                             "' with an equivalent definition: replacing [" + oldBeanDefinition +
46                             "] with [" + beanDefinition + "]");
47                 }
48             }
49             this.beanDefinitionMap.put(beanName, beanDefinition);
50         }
51         else {
52             if (hasBeanCreationStarted()) {
53                 // Cannot modify startup-time collection elements anymore (for stable iteration)
54                 synchronized (this.beanDefinitionMap) {
55                     this.beanDefinitionMap.put(beanName, beanDefinition);
56                     List<String> updatedDefinitions = new ArrayList<String>(this.beanDefinitionNames.size() + 1);
57                     updatedDefinitions.addAll(this.beanDefinitionNames);
58                     updatedDefinitions.add(beanName);
59                     this.beanDefinitionNames = updatedDefinitions;
60                     if (this.manualSingletonNames.contains(beanName)) {
61                         Set<String> updatedSingletons = new LinkedHashSet<String>(this.manualSingletonNames);
62                         updatedSingletons.remove(beanName);
63                         this.manualSingletonNames = updatedSingletons;
64                     }
65                 }
66             }
67             else {
68                 // Still in startup registration phase
69                 this.beanDefinitionMap.put(beanName, beanDefinition);
70                 this.beanDefinitionNames.add(beanName);
71                 this.manualSingletonNames.remove(beanName);
72             }
73             this.frozenBeanDefinitionNames = null;
74         }
75 
76         if (oldBeanDefinition != null || containsSingleton(beanName)) {
77             resetBeanDefinition(beanName);
78         }
79     }

第10行對這個BeanDefinition進行驗證,如果這個BeanDefinition有需要重載的方法,並且還存在工廠方法,那就報錯,這兩者不能共存。靜態工廠必須創建bean的實例

什么是重載的方法,比如使用了lookup-method,replace-method這些標簽,比如:

<bean id="service" class="com.test.UserService" scope="prototype" />

<bean id="userService" class="com.test.UserServiceCreator">

  <lookup-method name="getService" bean="server" />  

</bean>

我們調用UserServiceCreator的getService,取出來的值是UseService的實例,如果此時我們把UserSericeCreator設置一個靜態工廠方法,修改成下面這種

<bean id="userService" class="com.test.UserServiceCreator" factory-method="createService">

  <lookup-method name="getService" bean="server" />  

</bean>

這樣配置是錯誤的,在Spring創建bean實例的時候,spring就不知你要創建的是哪個對象了,這個id為userService的bean應該是UserServiceCreator的代理實例(方法重載會用到動態代理)還是工廠方法createService創建的UserService實例,所以只能報錯。

第20行是獲得老的BeanDefinition,如果存在老的BeanDefinition,就檢查是否允許覆蓋

第49行將定義好的BeanDefinition存到BeanFactory的beanDefinitionMap中,覆蓋oldBeanDefinition

如果不存在oldBeanDefinition,那么跳到52行,判斷是不是已經開始開始創建bean了,內部代碼只是判斷bean工廠的屬性alreadyCreated集合是否不為空,為空就表示還沒有開始,不為空表示開始了

第69行將BeanDefinition注冊到容器中,第70行將BeanDefinition的名字注入到容器中

創建好AspectJAwareAdvisorAutoProxyCreator類的BeanDefinition后,繼續調用了AopNamespaceUtils的useClassProxyingIfNecessary方法

 1 private static void useClassProxyingIfNecessary(BeanDefinitionRegistry registry, Element sourceElement) {
 2         if (sourceElement != null) {
 3             boolean proxyTargetClass = Boolean.valueOf(sourceElement.getAttribute(PROXY_TARGET_CLASS_ATTRIBUTE));
 4             if (proxyTargetClass) {
 5                 AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
 6             }
 7             boolean exposeProxy = Boolean.valueOf(sourceElement.getAttribute(EXPOSE_PROXY_ATTRIBUTE));
 8             if (exposeProxy) {
 9                 AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
10             }
11         }
12     }

第3行的PROXY_TARGET_CLASS_ATTRIBUTE的值為proxy-target-class,如果這個屬性為true那么就使用cglib做代理,默認為false使用JDK的動態代理

進入第5行的forceAutoProxyCreatorToUseClassProxying方法

if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
            BeanDefinition definition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
            definition.getPropertyValues().add("proxyTargetClass", Boolean.TRUE);
        }

很顯然BeanFactory中是存在AUTO_PROXY_CREATOR_BEAN_NAME的,這個key對應對象是AspectJAwareAdvisorAutoProxyCreator的BeanDefinition,前面已經說過了。

如果存在就給這個BeanDefinition添加屬性值proxyTargetClass為true,表示將使用cglib進行代理,后面創建代理類的時候會再次提到

第7行判斷當前是否需要暴露代理

useClassProxyingIfNecessary方法調用結束后有調用了AopNamespaceUtils的registerComponentIfNecessary方法

 

1 private static void registerComponentIfNecessary(BeanDefinition beanDefinition, ParserContext parserContext) {
2         if (beanDefinition != null) {
3             BeanComponentDefinition componentDefinition =
4                     new BeanComponentDefinition(beanDefinition, AopConfigUtils.AUTO_PROXY_CREATOR_BEAN_NAME);
5             parserContext.registerComponent(componentDefinition);
6         }
7     }

第4行代碼內部調用了以下這個方法,它在尋找propertyValues中是否有嵌入的BeanDefinition,BeanDefinitionHolder

 1 private void findInnerBeanDefinitionsAndBeanReferences(BeanDefinition beanDefinition) {
 2         List<BeanDefinition> innerBeans = new ArrayList<BeanDefinition>();
 3         List<BeanReference> references = new ArrayList<BeanReference>();
 4         PropertyValues propertyValues = beanDefinition.getPropertyValues();
 5         for (int i = 0; i < propertyValues.getPropertyValues().length; i++) {
 6             PropertyValue propertyValue = propertyValues.getPropertyValues()[i];
 7             Object value = propertyValue.getValue();
 8             if (value instanceof BeanDefinitionHolder) {
 9                 innerBeans.add(((BeanDefinitionHolder) value).getBeanDefinition());
10             }
11             else if (value instanceof BeanDefinition) {
12                 innerBeans.add((BeanDefinition) value);
13             }
14             else if (value instanceof BeanReference) {
15                 references.add((BeanReference) value);
16             }
17         }
18         this.innerBeanDefinitions = innerBeans.toArray(new BeanDefinition[innerBeans.size()]);
19         this.beanReferences = references.toArray(new BeanReference[references.size()]);
20     }

返回到上一層

1 private static void registerComponentIfNecessary(BeanDefinition beanDefinition, ParserContext parserContext) {
2         if (beanDefinition != null) {
3             BeanComponentDefinition componentDefinition =
4                     new BeanComponentDefinition(beanDefinition, AopConfigUtils.AUTO_PROXY_CREATOR_BEAN_NAME);
5             parserContext.registerComponent(componentDefinition);
6         }
7     }

這個BeanComponentDefinition類是BeanDefinitionHolder的子類,從名字可以看出它叫BeanDefinition持有者,內部有一個beanName屬性,相對應就有個BeanDefinition屬性

第5行將這個復合的BeanDefinitionHolder注冊到了ParseContext的一個叫containingComponents的stack中

這些方法調用完成后我們直接返回到ConfigBeanDefinitionParser類的parse方法。之前我們分析的是下面方法的第6行的configureAutoProxyCreator方法,有點繞,自己分析的時候需要結合

序列圖來看源碼

 1 public BeanDefinition parse(Element element, ParserContext parserContext) {
 2         CompositeComponentDefinition compositeDef =
 3                 new CompositeComponentDefinition(element.getTagName(), parserContext.extractSource(element));
 4         parserContext.pushContainingComponent(compositeDef);
 5 
 6         configureAutoProxyCreator(parserContext, element);
 7 
 8         List<Element> childElts = DomUtils.getChildElements(element);
 9         for (Element elt: childElts) {
10             String localName = parserContext.getDelegate().getLocalName(elt);
11             if (POINTCUT.equals(localName)) {
12                 parsePointcut(elt, parserContext);
13             }
14             else if (ADVISOR.equals(localName)) {
15                 parseAdvisor(elt, parserContext);
16             }
17             else if (ASPECT.equals(localName)) {
18                 parseAspect(elt, parserContext);
19             }
20         }
21 
22         parserContext.popAndRegisterContainingComponent();
23         return null;
24     }

第8行取得了<aop:config>的子元素,我這里就一個子元素<aop:aspect>

循環遍歷子元素,下面是ConfigBeanDefinitionParser類定義的標簽元素

class ConfigBeanDefinitionParser implements BeanDefinitionParser {

    private static final String ASPECT = "aspect";
    private static final String EXPRESSION = "expression";
    private static final String ID = "id";
    private static final String POINTCUT = "pointcut";
    private static final String ADVICE_BEAN_NAME = "adviceBeanName";
    private static final String ADVISOR = "advisor";
    private static final String ADVICE_REF = "advice-ref";
    private static final String POINTCUT_REF = "pointcut-ref";
    private static final String REF = "ref";
    private static final String BEFORE = "before";
    private static final String DECLARE_PARENTS = "declare-parents";
    private static final String TYPE_PATTERN = "types-matching";
    private static final String DEFAULT_IMPL = "default-impl";
    private static final String DELEGATE_REF = "delegate-ref";
    private static final String IMPLEMENT_INTERFACE = "implement-interface";
    private static final String AFTER = "after";
    private static final String AFTER_RETURNING_ELEMENT = "after-returning";
    private static final String AFTER_THROWING_ELEMENT = "after-throwing";
    private static final String AROUND = "around";
    private static final String RETURNING = "returning";
    private static final String RETURNING_PROPERTY = "returningName";
    private static final String THROWING = "throwing";
    private static final String THROWING_PROPERTY = "throwingName";
    private static final String ARG_NAMES = "arg-names";
    private static final String ARG_NAMES_PROPERTY = "argumentNames";
    private static final String ASPECT_NAME_PROPERTY = "aspectName";
    private static final String DECLARATION_ORDER_PROPERTY = "declarationOrder";
    private static final String ORDER_PROPERTY = "order";
    private static final int METHOD_INDEX = 0;
    private static final int POINTCUT_INDEX = 1;
    private static final int ASPECT_INSTANCE_FACTORY_INDEX = 2;

上面這些靜態常量很眼熟吧。我的測試標簽是aop:aspect,所以我們直接跳到第18行,進入到parseAspect方法看看

 1 private void parseAspect(Element aspectElement, ParserContext parserContext) {
 2         String aspectId = aspectElement.getAttribute(ID);
 3         String aspectName = aspectElement.getAttribute(REF);
 4 
 5         try {
 6             this.parseState.push(new AspectEntry(aspectId, aspectName));
 7             List<BeanDefinition> beanDefinitions = new ArrayList<BeanDefinition>();
 8             List<BeanReference> beanReferences = new ArrayList<BeanReference>();
 9 
10             List<Element> declareParents = DomUtils.getChildElementsByTagName(aspectElement, DECLARE_PARENTS);
11             for (int i = METHOD_INDEX; i < declareParents.size(); i++) {
12                 Element declareParentsElement = declareParents.get(i);
13                 beanDefinitions.add(parseDeclareParents(declareParentsElement, parserContext));
14             }
15 
16             // We have to parse "advice" and all the advice kinds in one loop, to get the
17             // ordering semantics right.
18             NodeList nodeList = aspectElement.getChildNodes();
19             boolean adviceFoundAlready = false;
20             for (int i = 0; i < nodeList.getLength(); i++) {
21                 Node node = nodeList.item(i);
22                 if (isAdviceNode(node, parserContext)) {
23                     if (!adviceFoundAlready) {
24                         adviceFoundAlready = true;
25                         if (!StringUtils.hasText(aspectName)) {
26                             parserContext.getReaderContext().error(
27                                     "<aspect> tag needs aspect bean reference via 'ref' attribute when declaring advices.",
28                                     aspectElement, this.parseState.snapshot());
29                             return;
30                         }
31                         beanReferences.add(new RuntimeBeanReference(aspectName));
32                     }
33                     AbstractBeanDefinition advisorDefinition = parseAdvice(
34                             aspectName, i, aspectElement, (Element) node, parserContext, beanDefinitions, beanReferences);
35                     beanDefinitions.add(advisorDefinition);
36                 }
37             }
38 
39             AspectComponentDefinition aspectComponentDefinition = createAspectComponentDefinition(
40                     aspectElement, aspectId, beanDefinitions, beanReferences, parserContext);
41             parserContext.pushContainingComponent(aspectComponentDefinition);
42 
43             List<Element> pointcuts = DomUtils.getChildElementsByTagName(aspectElement, POINTCUT);
44             for (Element pointcutElement : pointcuts) {
45                 parsePointcut(pointcutElement, parserContext);
46             }
47 
48             parserContext.popAndRegisterContainingComponent();
49         }
50         finally {
51             this.parseState.pop();
52         }
53     }

第2,3行獲得ID和bean的引用

第6行將ID和ref包裝成一個entry壓入到一個叫做parseState的stack中

第10行意思是在aspect元素下尋找declare-parents子元素,這個故事告訴我們spring的助手類真的很好用。這個標簽是用於給某個類設置父類。如果對這個標簽感興趣可以去搜索相關的資料

第18行取得了aspect下的所有子元素

第22行判斷當前標簽是不是通知類型的標簽,具體的實現代碼如下

private boolean isAdviceNode(Node aNode, ParserContext parserContext) {
        if (!(aNode instanceof Element)) {
            return false;
        }
        else {
            String name = parserContext.getDelegate().getLocalName(aNode);
            return (BEFORE.equals(name) || AFTER.equals(name) || AFTER_RETURNING_ELEMENT.equals(name) ||
                    AFTER_THROWING_ELEMENT.equals(name) || AROUND.equals(name));
        }
    }

當找到通知類型的標簽,如aop:before,我們跳到第33行,看看parseAdvice方法

 1 private AbstractBeanDefinition parseAdvice(
 2             String aspectName, int order, Element aspectElement, Element adviceElement, ParserContext parserContext,
 3             List<BeanDefinition> beanDefinitions, List<BeanReference> beanReferences) {
 4 
 5         try {
 6             this.parseState.push(new AdviceEntry(parserContext.getDelegate().getLocalName(adviceElement)));
 7 
 8             // create the method factory bean
 9             RootBeanDefinition methodDefinition = new RootBeanDefinition(MethodLocatingFactoryBean.class);
10             methodDefinition.getPropertyValues().add("targetBeanName", aspectName);
11             methodDefinition.getPropertyValues().add("methodName", adviceElement.getAttribute("method"));
12             methodDefinition.setSynthetic(true);
13 
14             // create instance factory definition
15             RootBeanDefinition aspectFactoryDef =
16                     new RootBeanDefinition(SimpleBeanFactoryAwareAspectInstanceFactory.class);
17             aspectFactoryDef.getPropertyValues().add("aspectBeanName", aspectName);
18             aspectFactoryDef.setSynthetic(true);
19 
20             // register the pointcut
21             AbstractBeanDefinition adviceDef = createAdviceDefinition(
22                     adviceElement, parserContext, aspectName, order, methodDefinition, aspectFactoryDef,
23                     beanDefinitions, beanReferences);
24 
25             // configure the advisor
26             RootBeanDefinition advisorDefinition = new RootBeanDefinition(AspectJPointcutAdvisor.class);
27             advisorDefinition.setSource(parserContext.extractSource(adviceElement));
28             advisorDefinition.getConstructorArgumentValues().addGenericArgumentValue(adviceDef);
29             if (aspectElement.hasAttribute(ORDER_PROPERTY)) {
30                 advisorDefinition.getPropertyValues().add(
31                         ORDER_PROPERTY, aspectElement.getAttribute(ORDER_PROPERTY));
32             }
33 
34             // register the final advisor
35             parserContext.getReaderContext().registerWithGeneratedName(advisorDefinition);
36 
37             return advisorDefinition;
38         }
39         finally {
40             this.parseState.pop();
41         }
42     }

第9行又創建了一個RootBeanDefinition的實例

第10行將切面的id和切面的方法保存到這個RootBeanDefinition中

主要看到第21createAdviceDefinition的代碼

 1 private AbstractBeanDefinition createAdviceDefinition(
 2             Element adviceElement, ParserContext parserContext, String aspectName, int order,
 3             RootBeanDefinition methodDef, RootBeanDefinition aspectFactoryDef,
 4             List<BeanDefinition> beanDefinitions, List<BeanReference> beanReferences) {
 5 
 6         RootBeanDefinition adviceDefinition = new RootBeanDefinition(getAdviceClass(adviceElement, parserContext));
 7         adviceDefinition.setSource(parserContext.extractSource(adviceElement));
 8         //添加切面名
 9         adviceDefinition.getPropertyValues().add(ASPECT_NAME_PROPERTY, aspectName);
10         adviceDefinition.getPropertyValues().add(DECLARATION_ORDER_PROPERTY, order);
11         //判斷是否存在returning屬性
12         if (adviceElement.hasAttribute(RETURNING)) {
13             adviceDefinition.getPropertyValues().add(
14                     RETURNING_PROPERTY, adviceElement.getAttribute(RETURNING));
15         }
16         if (adviceElement.hasAttribute(THROWING)) {
17             adviceDefinition.getPropertyValues().add(
18                     THROWING_PROPERTY, adviceElement.getAttribute(THROWING));
19         }
//判斷是否有參數
20 if (adviceElement.hasAttribute(ARG_NAMES)) { 21 adviceDefinition.getPropertyValues().add( 22 ARG_NAMES_PROPERTY, adviceElement.getAttribute(ARG_NAMES)); 23 } 24 25 ConstructorArgumentValues cav = adviceDefinition.getConstructorArgumentValues(); 26 cav.addIndexedArgumentValue(METHOD_INDEX, methodDef); 27 28 Object pointcut = parsePointcutProperty(adviceElement, parserContext); 29 if (pointcut instanceof BeanDefinition) { 30 cav.addIndexedArgumentValue(POINTCUT_INDEX, pointcut); 31 beanDefinitions.add((BeanDefinition) pointcut); 32 } 33 else if (pointcut instanceof String) { 34 RuntimeBeanReference pointcutRef = new RuntimeBeanReference((String) pointcut); 35 cav.addIndexedArgumentValue(POINTCUT_INDEX, pointcutRef); 36 beanReferences.add(pointcutRef); 37 } 38 39 cav.addIndexedArgumentValue(ASPECT_INSTANCE_FACTORY_INDEX, aspectFactoryDef); 40 41 return adviceDefinition; 42 }

第28行從這個通知元素中解析切點引用pointcut-ref,如果你在這個通知標簽中使用的pointcut屬性,那么會返回一個BeanDefinition類型

講了這么多BeanDefinition,這個BeanDefinition到底是個什么東西,BeanDefinition翻譯過來就是bean定義的意思,相當於將xml文件中定義的Bean

翻譯成java代碼,如<bean id="hello" class="com.test.Hello" scope="singleton" />在BeanDefinition這個類中會都會有相對應的屬性,它也有id

有className,有scope,有initMethodName,有destroyMethodName這些個屬性,就相當於把xml定義的bean翻譯成java代碼。

通知類型的標簽設置完成后,我們再看看pointcut的解析

 1 private AbstractBeanDefinition parsePointcut(Element pointcutElement, ParserContext parserContext) {
 2         String id = pointcutElement.getAttribute(ID);
 3         String expression = pointcutElement.getAttribute(EXPRESSION);
 4 
 5         AbstractBeanDefinition pointcutDefinition = null;
 6 
 7         try {
 8             this.parseState.push(new PointcutEntry(id));
 9             pointcutDefinition = createPointcutDefinition(expression);
10             pointcutDefinition.setSource(parserContext.extractSource(pointcutElement));
11 
12             String pointcutBeanName = id;
13             if (StringUtils.hasText(pointcutBeanName)) {
14                 parserContext.getRegistry().registerBeanDefinition(pointcutBeanName, pointcutDefinition);
15             }
16             else {
17                 pointcutBeanName = parserContext.getReaderContext().registerWithGeneratedName(pointcutDefinition);
18             }
19 
20             parserContext.registerComponent(
21                     new PointcutComponentDefinition(pointcutBeanName, pointcutDefinition, expression));
22         }
23         finally {
24             this.parseState.pop();
25         }
26 
27         return pointcutDefinition;
28     }

 第9行創建了一個屬性className為AspectJExpressionPointcut的BeanDefinition,具體這個拿來干嘛的,到后面使用到的時候再說,一路debug過來,定義了一大堆的BeanDefinition

都是為后面創建bean做准備

第14行把創建的切點BeanDefinition注冊到BeanFactory中

至此可以發現,所謂的xml的解析,都是將相應的配置信息解析出來封裝成一個叫做BeanDefinition的對象,最后注冊到BeanFactory的BeanDefinitionMap的map容器中

aop:config解析完成后,我們看看bean標簽的解析,bean是屬於默認的命名空間中定義的標簽,解析時使用的DefaultBeanDefinitionDocumentReader類的parseDefaultElement方法

 1 private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
 2         if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
 3             importBeanDefinitionResource(ele);
 4         }
 5         else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
 6             processAliasRegistration(ele);
 7         }
 8         else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
 9             processBeanDefinition(ele, delegate);
10         }
11         else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
12             // recurse
13             doRegisterBeanDefinitions(ele);
14         }
15     }

我們解析的是bean標簽,所以直接跳到第8行,看看processBeanDefinition方法

 1 protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
 2         BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
 3         if (bdHolder != null) {
 4             bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
 5             try {
 6                 // Register the final decorated instance.
 7                 BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
 8             }
 9             catch (BeanDefinitionStoreException ex) {
10                 getReaderContext().error("Failed to register bean definition with name '" +
11                         bdHolder.getBeanName() + "'", ele, ex);
12             }
13             // Send registration event.
14             getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
15         }
16     }

進入第2行的parseBeanDefinitionElement

 1 public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {
 2         String id = ele.getAttribute(ID_ATTRIBUTE);//取得bean標簽的id
 3         String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);//取得Bean標簽的name屬性  4 
 5         List<String> aliases = new ArrayList<String>();
 6         if (StringUtils.hasLength(nameAttr)) {
 7             String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);//將name屬性的到的名字按,分割,並作為別名  8             aliases.addAll(Arrays.asList(nameArr));
 9         }
10 
11         String beanName = id;
12         if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
13             beanName = aliases.remove(0);
14             if (logger.isDebugEnabled()) {
15                 logger.debug("No XML 'id' specified - using '" + beanName +
16                         "' as bean name and " + aliases + " as aliases");
17             }
18         }
19 
20         if (containingBean == null) {
21             checkNameUniqueness(beanName, aliases, ele);
22         }
23 
24         AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
25         if (beanDefinition != null) {
26             if (!StringUtils.hasText(beanName)) {
27                 try {
28                     if (containingBean != null) {
29                         beanName = BeanDefinitionReaderUtils.generateBeanName(
30                                 beanDefinition, this.readerContext.getRegistry(), true);
31                     }
32                     else {
33                         beanName = this.readerContext.generateBeanName(beanDefinition);
34                         // Register an alias for the plain bean class name, if still possible,
35                         // if the generator returned the class name plus a suffix.
36                         // This is expected for Spring 1.2/2.0 backwards compatibility.
37                         String beanClassName = beanDefinition.getBeanClassName();
38                         if (beanClassName != null &&
39                                 beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
40                                 !this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
41                             aliases.add(beanClassName);
42                         }
43                     }
44                     if (logger.isDebugEnabled()) {
45                         logger.debug("Neither XML 'id' nor 'name' specified - " +
46                                 "using generated bean name [" + beanName + "]");
47                     }
48                 }
49                 catch (Exception ex) {
50                     error(ex.getMessage(), ele);
51                     return null;
52                 }
53             }
54             String[] aliasesArray = StringUtils.toStringArray(aliases);
55             return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
56         }
57 
58         return null;
59     }

第12表示,如果存在id和name,並且id沒有值,name有值,那么就取name的第一個name值做為beanName

第21行,對beanName和別名進行檢查,BeanDefinitionParserDelegate類中有個usedNames容器,這個容器用於保存已經使用了的beanName,所以這個方法是在檢查是否有重復定義的beanName或者別名

第24行又將bean標簽翻譯成了一個BeanDefinition,它是怎么翻譯的等下再說,先往下看

第29行,如果這個bean沒有指定beanName,那么就自己生成一個,一般是這個bean類的類名加上#在加一個數字,這個數字是從零開始的,這個數字要看這個bean是BeanFactory中的第幾個沒有寫beanName的bean了,他叫什么,這不是重點,我們一般也不會去寫個沒有beanName的bean,不寫beanName的情況一般是給spring通過類型來自動注入

下面開始講講它是怎么解析成BeanDefinition的

 1 String className = null;
 2         if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
 3             className = ele.getAttribute(CLASS_ATTRIBUTE).trim();//獲得class屬性定義的className  4         }
 5 
 6         try {
 7             String parent = null;
 8             if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
 9                 parent = ele.getAttribute(PARENT_ATTRIBUTE); //如果有parent屬性就獲取到parent屬性的值 10             }
11             AbstractBeanDefinition bd = createBeanDefinition(className, parent);//創建一個BeanDefinition對象 12 
13             parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
14             bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));//如果這個bean元素有description子標簽,獲得他的值設置到BeanDefinition中 15 
16             parseMetaElements(ele, bd);//解析元標簽<meta key="" value="">,當需要用到的時候,可以用過BeanDefinition的getAttribute(key)獲得 17             parseLookupOverrideSubElements(ele, bd.getMethodOverrides());//解析bean標簽中是夠含有lookup-method標簽,如果有就設置到methodOverrides中 18             parseReplacedMethodSubElements(ele, bd.getMethodOverrides());//解析replace-method標簽 19 
20             parseConstructorArgElements(ele, bd);//解析構造器參數 21             parsePropertyElements(ele, bd);//解析property標簽 22             parseQualifierElements(ele, bd);//解析qualifier 23 
24             bd.setResource(this.readerContext.getResource());
25             bd.setSource(extractSource(ele));
26 
27             return bd;

 

看到第13行,這個方法是用來解析bean定義的屬性的

 1 public AbstractBeanDefinition parseBeanDefinitionAttributes(Element ele, String beanName,
 2             BeanDefinition containingBean, AbstractBeanDefinition bd) {
 3 
 4         if (ele.hasAttribute(SINGLETON_ATTRIBUTE)) {//如果存在singleton這個屬性,就解析,當不做任何處理,提示用戶過時了,應該使用scope來代替  5             error("Old 1.x 'singleton' attribute in use - upgrade to 'scope' declaration", ele);
 6         }
 7         else if (ele.hasAttribute(SCOPE_ATTRIBUTE)) {//如果存在scope屬性就取得取得他的值,並設置到BeanDefinition中  8             bd.setScope(ele.getAttribute(SCOPE_ATTRIBUTE));
 9         }
10         else if (containingBean != null) {
11             // Take default from containing bean in case of an inner bean definition.
12             bd.setScope(containingBean.getScope());
13         }
14 
15         if (ele.hasAttribute(ABSTRACT_ATTRIBUTE)) {
16             bd.setAbstract(TRUE_VALUE.equals(ele.getAttribute(ABSTRACT_ATTRIBUTE)));
17         }
18 
19         String lazyInit = ele.getAttribute(LAZY_INIT_ATTRIBUTE);
20         if (DEFAULT_VALUE.equals(lazyInit)) {
21             lazyInit = this.defaults.getLazyInit();
22         }
23         bd.setLazyInit(TRUE_VALUE.equals(lazyInit));
24 
25         String autowire = ele.getAttribute(AUTOWIRE_ATTRIBUTE);
26         bd.setAutowireMode(getAutowireMode(autowire));
27 
28         String dependencyCheck = ele.getAttribute(DEPENDENCY_CHECK_ATTRIBUTE);
29         bd.setDependencyCheck(getDependencyCheck(dependencyCheck));
30 
31         if (ele.hasAttribute(DEPENDS_ON_ATTRIBUTE)) {
32             String dependsOn = ele.getAttribute(DEPENDS_ON_ATTRIBUTE);
33             bd.setDependsOn(StringUtils.tokenizeToStringArray(dependsOn, MULTI_VALUE_ATTRIBUTE_DELIMITERS));
34         }
35 
36         String autowireCandidate = ele.getAttribute(AUTOWIRE_CANDIDATE_ATTRIBUTE);
37         if ("".equals(autowireCandidate) || DEFAULT_VALUE.equals(autowireCandidate)) {
38             String candidatePattern = this.defaults.getAutowireCandidates();
39             if (candidatePattern != null) {
40                 String[] patterns = StringUtils.commaDelimitedListToStringArray(candidatePattern);
41                 bd.setAutowireCandidate(PatternMatchUtils.simpleMatch(patterns, beanName));
42             }
43         }
44         else {
45             bd.setAutowireCandidate(TRUE_VALUE.equals(autowireCandidate));
46         }
47 
48         if (ele.hasAttribute(PRIMARY_ATTRIBUTE)) {
49             bd.setPrimary(TRUE_VALUE.equals(ele.getAttribute(PRIMARY_ATTRIBUTE)));
50         }
51 
52         if (ele.hasAttribute(INIT_METHOD_ATTRIBUTE)) {
53             String initMethodName = ele.getAttribute(INIT_METHOD_ATTRIBUTE);
54             if (!"".equals(initMethodName)) {
55                 bd.setInitMethodName(initMethodName);
56             }
57         }
58         else {
59             if (this.defaults.getInitMethod() != null) {
60                 bd.setInitMethodName(this.defaults.getInitMethod());
61                 bd.setEnforceInitMethod(false);
62             }
63         }
64 
65         if (ele.hasAttribute(DESTROY_METHOD_ATTRIBUTE)) {
66             String destroyMethodName = ele.getAttribute(DESTROY_METHOD_ATTRIBUTE);
67             bd.setDestroyMethodName(destroyMethodName);
68         }
69         else {
70             if (this.defaults.getDestroyMethod() != null) {
71                 bd.setDestroyMethodName(this.defaults.getDestroyMethod());
72                 bd.setEnforceDestroyMethod(false);
73             }
74         }
75 
76         if (ele.hasAttribute(FACTORY_METHOD_ATTRIBUTE)) {
77             bd.setFactoryMethodName(ele.getAttribute(FACTORY_METHOD_ATTRIBUTE));
78         }
79         if (ele.hasAttribute(FACTORY_BEAN_ATTRIBUTE)) {
80             bd.setFactoryBeanName(ele.getAttribute(FACTORY_BEAN_ATTRIBUTE));
81         }
82 
83         return bd;
84     }

將bean標簽中所有的屬性進行讀取,有定義的就讀過來設置到BeanDefinition中,如果沒有的自然是使用默認值,解析完bean標簽上的屬性后,自然還有解析bean

標簽里面的子標簽,這里選擇其中解析property解析下,下面是部分源碼

 1 String propertyName = ele.getAttribute(NAME_ATTRIBUTE);//獲取property標簽上的那么屬性  2         if (!StringUtils.hasLength(propertyName)) {
 3             error("Tag 'property' must have a 'name' attribute", ele);
 4             return;
 5         }
 6         this.parseState.push(new PropertyEntry(propertyName));
 7         try {
 8             if (bd.getPropertyValues().contains(propertyName)) {
 9                 error("Multiple 'property' definitions for property '" + propertyName + "'", ele);
10                 return;
11             }
12             Object val = parsePropertyValue(ele, bd, propertyName);
13             PropertyValue pv = new PropertyValue(propertyName, val);//將屬性值和對應的value打包成一個PropertyValue 14             parseMetaElements(ele, pv);
15             pv.setSource(extractSource(ele));
16             bd.getPropertyValues().addPropertyValue(pv);//將包含屬性值和值得propertyValue設置到BeanDefinition中

我們看到第12行內部的部分代碼

 1 if (hasRefAttribute) {
 2             String refName = ele.getAttribute(REF_ATTRIBUTE);
 3             if (!StringUtils.hasText(refName)) {
 4                 error(elementName + " contains empty 'ref' attribute", ele);
 5             }
 6             RuntimeBeanReference ref = new RuntimeBeanReference(refName);
 7             ref.setSource(extractSource(ele));
 8             return ref;
 9         }
10         else if (hasValueAttribute) {
11             TypedStringValue valueHolder = new TypedStringValue(ele.getAttribute(VALUE_ATTRIBUTE));
12             valueHolder.setSource(extractSource(ele));
13             return valueHolder;
14         }

第2行去獲得ref屬性的值,並且把這個值包裝成一個RuntimeBeanReference對象

第11行,如果不是個ref類型的值(value屬性指定的值)就被包裝成TypedStringValue類型的對象。

 

回到processBeanDefinition方法

 1 protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
 2         BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
 3         if (bdHolder != null) {
 4             bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
 5             try {
 6                 // Register the final decorated instance.
 7                 BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
 8             }
 9             catch (BeanDefinitionStoreException ex) {
10                 getReaderContext().error("Failed to register bean definition with name '" +
11                         bdHolder.getBeanName() + "'", ele, ex);
12             }
13             // Send registration event.
14             getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
15         }
16     }

第四行又對BeanDefinitionHolder做了些裝飾,這個方法的作用,主要是用來解析bean中嵌套的自定標簽,如<bean id="" class=""><mytag:test /></bean>

在這里順便再分析一下bean中construct-arg的解析方式

 1 public void parseConstructorArgElement(Element ele, BeanDefinition bd) {
 2         String indexAttr = ele.getAttribute(INDEX_ATTRIBUTE);//獲取index屬性的值  3         String typeAttr = ele.getAttribute(TYPE_ATTRIBUTE);//獲取type屬性的值  4         String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);//獲取name屬性的值  5         if (StringUtils.hasLength(indexAttr)) {
 6             try {
 7                 int index = Integer.parseInt(indexAttr);
 8                 if (index < 0) {
 9                     error("'index' cannot be lower than 0", ele);
10                 }
11                 else {
12                     try {
13                         this.parseState.push(new ConstructorArgumentEntry(index));
14                         Object value = parsePropertyValue(ele, bd, null);//這段代碼和解析property標簽的方式一樣,對ref的值包裝成RuntimeBeanReference實例,value包裝成TypeStringValue的實例 15                         ConstructorArgumentValues.ValueHolder valueHolder = new ConstructorArgumentValues.ValueHolder(value);
16                         if (StringUtils.hasLength(typeAttr)) {
17                             valueHolder.setType(typeAttr);
18                         }
19                         if (StringUtils.hasLength(nameAttr)) {
20                             valueHolder.setName(nameAttr);
21                         }
22                         valueHolder.setSource(extractSource(ele));
23                         if (bd.getConstructorArgumentValues().hasIndexedArgumentValue(index)) {
24                             error("Ambiguous constructor-arg entries for index " + index, ele);
25                         }
26                         else {
27                             bd.getConstructorArgumentValues().addIndexedArgumentValue(index, valueHolder);
28                         }
29                     }
30                     finally {
31                         this.parseState.pop();
32                     }
33                 }
34             }
35             catch (NumberFormatException ex) {
36                 error("Attribute 'index' of tag 'constructor-arg' must be an integer", ele);
37             }
38         }
39         else {
40             try {
41                 this.parseState.push(new ConstructorArgumentEntry());
42                 Object value = parsePropertyValue(ele, bd, null);
43                 ConstructorArgumentValues.ValueHolder valueHolder = new ConstructorArgumentValues.ValueHolder(value);
44                 if (StringUtils.hasLength(typeAttr)) {
45                     valueHolder.setType(typeAttr);
46                 }
47                 if (StringUtils.hasLength(nameAttr)) {
48                     valueHolder.setName(nameAttr);
49                 }
50                 valueHolder.setSource(extractSource(ele));
51                 bd.getConstructorArgumentValues().addGenericArgumentValue(valueHolder);
52             }
53             finally {
54                 this.parseState.pop();
55             }
56         }
57     }

 

其實和解析property相同的套路,不同在與,property的是將返回回來的value用添加到了BeanDefinition的propertyValues屬性中,而構造器標簽對value的封裝使用了

ConstructorArgumentValues.ValueHolder值持有者來封裝,並把這個值存放到BeanDefinition的
indexedArgumentValue屬性中

一切都准備就緒了,各種屬性都設置到為了BeanDefinition中了,那么剩下的就是注冊到BeanFactory中了
 1 public static void registerBeanDefinition(
 2             BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
 3             throws BeanDefinitionStoreException {
 4 
 5         // Register bean definition under primary name.
 6         String beanName = definitionHolder.getBeanName();
 7         registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
 8 
 9         // Register aliases for bean name, if any.
10         String[] aliases = definitionHolder.getAliases();
11         if (aliases != null) {
12             for (String alias : aliases) {
13                 registry.registerAlias(beanName, alias);
14             }
15         }
16     }

看到第7行的代碼有沒有似曾相識的感覺,我們在分析aop:config的時候就已經分析過了,如果忘記了往上翻,這里就不再重復說了,現在主要是看第13的代碼,別名的注冊

 1 public void registerAlias(String name, String alias) {
 2         Assert.hasText(name, "'name' must not be empty");
 3         Assert.hasText(alias, "'alias' must not be empty");
 4         if (alias.equals(name)) {//如果別名和beanName相同,那么就刪掉它,不需要別名  5             this.aliasMap.remove(alias);
 6         }
 7         else {
 8             String registeredName = this.aliasMap.get(alias);//如果這個別名已經存在就拿出對應的beanName  9             if (registeredName != null) {
10                 if (registeredName.equals(name)) {//如果對應的beanName是相同的,那么就無需再次注冊了 11                     // An existing alias - no need to re-register
12                     return;
13                 }
14                 if (!allowAliasOverriding()) {//如果不相等,就判斷是否允許別名覆蓋 15                     throw new IllegalStateException("Cannot register alias '" + alias + "' for name '" +
16                             name + "': It is already registered for name '" + registeredName + "'.");
17                 }
18             }
19             checkForAliasCircle(name, alias);
20             this.aliasMap.put(alias, name);
21         }
22     }

第19行進行別名循環依賴檢查,如果出現a能找到b,b又能找c,c又能找到a就會出錯

 

當xml中所有的標簽解析成BeanDefinition后,xml的解析工作也就結束了,接下來要做的事情就是創建bean了。

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM