Spring IOC 源码阅读资源加载和注册

来源:互联网 发布:销售系统源码 编辑:程序博客网 时间:2024/05/16 19:09

   上面讲到,spring在查找到资源以后,在BeanDefinitionReader的loadBeanDefinitions(String location)方法中,接着就调用了int loadCount = loadBeanDefinitions(resources);

   这个方法间接的调用了子类XmlBeanDifinitionReader的loadBeanDefinitions(EncodedResource encodedResource)方法:

[java] view plain copy
  1. <span style="font-size:12px;">/** 
  2.      * Load bean definitions from the specified XML file. 
  3.      * @param encodedResource the resource descriptor for the XML file, 
  4.      * allowing to specify an encoding to use for parsing the file 
  5.      * @return the number of bean definitions found 
  6.      * @throws BeanDefinitionStoreException in case of loading or parsing errors 
  7.      */  
  8.     public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {  
  9.         Assert.notNull(encodedResource, "EncodedResource must not be null");  
  10.         if (logger.isInfoEnabled()) {  
  11.             logger.info("Loading XML bean definitions from " + encodedResource.getResource());  
  12.         }  
  13.   
  14.         Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();  
  15.         if (currentResources == null) {  
  16.             currentResources = new HashSet<EncodedResource>(4);  
  17.             this.resourcesCurrentlyBeingLoaded.set(currentResources);  
  18.         }  
  19.         //当前的资源正在加载--我猜的  
  20.         if (!currentResources.add(encodedResource)) {  
  21.             throw new BeanDefinitionStoreException(  
  22.                     "Detected cyclic loading of " + encodedResource + " - check your import definitions!");  
  23.         }  
  24.         try {  
  25.             InputStream inputStream = encodedResource.getResource().getInputStream();  
  26.             try {  
  27.                 InputSource inputSource = new InputSource(inputStream);  
  28.                 if (encodedResource.getEncoding() != null) {  
  29.                     inputSource.setEncoding(encodedResource.getEncoding());  
  30.                 }  
  31.                 <span style="color:#ff0000;">return doLoadBeanDefinitions(inputSource, encodedResource.getResource());</span>  
  32.             }  
  33.             finally {  
  34.                 inputStream.close();  
  35.             }  
  36.         }  
  37.         catch (IOException ex) {  
  38.             throw new BeanDefinitionStoreException(  
  39.                     "IOException parsing XML document from " + encodedResource.getResource(), ex);  
  40.         }  
  41.         finally {  
  42.             currentResources.remove(encodedResource);  
  43.             if (currentResources.isEmpty()) {  
  44.                 this.resourcesCurrentlyBeingLoaded.remove();  
  45.             }  
  46.         }  
  47.     }</span>  


上述方法调用了doLoadBeanDefinitions(InputSource inputSource, Resource resource)方法:

 

[java] view plain copy
  1. /** 
  2.      * Actually load bean definitions from the specified XML file. 
  3.      * @param inputSource the SAX InputSource to read from 
  4.      * @param resource the resource descriptor for the XML file 
  5.      * @return the number of bean definitions found 
  6.      * @throws BeanDefinitionStoreException in case of loading or parsing errors 
  7.      */  
  8.     protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)  
  9.             throws BeanDefinitionStoreException {  
  10.         try {  
  11.             int validationMode = getValidationModeForResource(resource);  
  12.             <span style="color:#ff0000;">Document doc = this.documentLoader.loadDocument(  
  13.                     inputSource, getEntityResolver(), this.errorHandler, validationMode, isNamespaceAware());  
  14.             return registerBeanDefinitions(doc, resource);  
  15. </span>     }  
  16.         catch (BeanDefinitionStoreException ex) {  
  17.             throw ex;  
  18.         }  
  19.         catch (SAXParseException ex) {  
  20.             throw new XmlBeanDefinitionStoreException(resource.getDescription(),  
  21.                     "Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex);  
  22.         }  
  23.         catch (SAXException ex) {  
  24.             throw new XmlBeanDefinitionStoreException(resource.getDescription(),  
  25.                     "XML document from " + resource + " is invalid", ex);  
  26.         }  
  27.         catch (ParserConfigurationException ex) {  
  28.             throw new BeanDefinitionStoreException(resource.getDescription(),  
  29.                     "Parser configuration exception parsing XML from " + resource, ex);  
  30.         }  
  31.         catch (IOException ex) {  
  32.             throw new BeanDefinitionStoreException(resource.getDescription(),  
  33.                     "IOException parsing XML document from " + resource, ex);  
  34.         }  
  35.         catch (Throwable ex) {  
  36.             throw new BeanDefinitionStoreException(resource.getDescription(),  
  37.                     "Unexpected exception parsing XML document from " + resource, ex);  
  38.         }  
  39.     }  

在上面的方法中将xml人间解析成了document对象,然后调用了registerBeanDefinitions(Document doc, Resource resource)方法:

[java] view plain copy
  1.     /** 
  2.      * Register the bean definitions contained in the given DOM document. 
  3.      * Called by <code>loadBeanDefinitions</code>. 
  4.      * <p>Creates a new instance of the parser class and invokes 
  5.      * <code>registerBeanDefinitions</code> on it. 
  6.      * @param doc the DOM document 
  7.      * @param resource the resource descriptor (for context information) 
  8.      * @return the number of bean definitions found 
  9.      * @throws BeanDefinitionStoreException in case of parsing errors 
  10.      * @see #loadBeanDefinitions 
  11.      * @see #setDocumentReaderClass 
  12.      * @see BeanDefinitionDocumentReader#registerBeanDefinitions 
  13.      */  
  14.     public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {  
  15.         BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();  
  16.         documentReader.setEnvironment(this.getEnvironment());  
  17.         int countBefore = getRegistry().getBeanDefinitionCount();  
  18.         <span style="color:#ff0000;">documentReader.registerBeanDefinitions(doc, createReaderContext(resource));  
  19. </span>     return getRegistry().getBeanDefinitionCount() - countBefore;  
  20.     }  

在上面的方法中先创建了一个DocumentReader对象,然后调用DefaultBeanDifinitionDocumentReader的registerBeanDefinitions(Document doc, XmlReaderContext readerContext)方法,此方法调用了下面的方法

[java] view plain copy
  1. /** 
  2.  * Register each bean definition within the given root {@code <beans/>} element. 
  3.  * @throws IllegalStateException if {@code <beans profile="..."} attribute is present 
  4.  * and Environment property has not been set 
  5.  * @see #setEnvironment 
  6.  */  
  7. protected void doRegisterBeanDefinitions(Element root) {  
  8.     String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);  
  9.     if (StringUtils.hasText(profileSpec)) {  
  10.         Assert.state(this.environment != null"environment property must not be null");  
  11.         String[] specifiedProfiles = StringUtils.tokenizeToStringArray(profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);  
  12.         if (!this.environment.acceptsProfiles(specifiedProfiles)) {  
  13.             return;  
  14.         }  
  15.     }  
  16.   
  17.     // any nested <beans> elements will cause recursion in this method. In  
  18.     // order to propagate and preserve <beans> default-* attributes correctly,  
  19.     // keep track of the current (parent) delegate, which may be null. Create  
  20.     // the new (child) delegate with a reference to the parent for fallback purposes,  
  21.     // then ultimately reset this.delegate back to its original (parent) reference.  
  22.     // this behavior emulates a stack of delegates without actually necessitating one.  
  23.     BeanDefinitionParserDelegate parent = this.delegate;  
  24.     this.delegate = createHelper(readerContext, root, parent);  
  25.   
  26.     preProcessXml(root);  
  27.     <span style="color:#ff0000;">parseBeanDefinitions(root, this.delegate);  
  28. /span>      postProcessXml(root);  
  29.   
  30.     this.delegate = parent;  
  31. }  


在这个方法中创建了解析beandefinition的委托对象,实际上所有的解析都是在这个委托对象中完成的。

再看上面的方法间接调用了下面的DefaultBeanDifinitionDocumentReader方法:

[java] view plain copy
  1. /** 
  2.  * Process the given bean element, parsing the bean definition 
  3.  * and registering it with the registry. 
  4.  */  
  5. protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {  
  6.     <span style="color:#ff0000;">BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);</span>  
  7.     if (bdHolder != null) {  
  8.         bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);  
  9.         try {  
  10.             // Register the final decorated instance.  
  11.             <span style="color:#ff0000;">BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());  
  12. /span>          }  
  13.         catch (BeanDefinitionStoreException ex) {  
  14.             getReaderContext().error("Failed to register bean definition with name '" +  
  15.                     bdHolder.getBeanName() + "'", ele, ex);  
  16.         }  
  17.         // Send registration event.  
  18.         getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));  
  19.     }  
  20. }  


上面红色的的两个方法一个是解析得到BeanDefinitionHolder对象,此对象持有BeanDefinition对象和bean的别名,id等信息。一个方法是注册解析得到的BeanDefinition。

 下面看看在BeanDefinitionParserDeleget类中的解析方法,

[html] view plain copy
  1. /**  
  2.  * Parses the supplied <code><bean></code> element. May return <code>null</code>  
  3.  * if there were errors during parse. Errors are reported to the  
  4.  * {@link org.springframework.beans.factory.parsing.ProblemReporter}.  
  5.  */  
  6. public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) {  
  7.     return parseBeanDefinitionElement(ele, null);  
  8. }  
  9.   
  10. /**  
  11.  * Parses the supplied <code><bean></code> element. May return <code>null</code>  
  12.  * if there were errors during parse. Errors are reported to the  
  13.  * {@link org.springframework.beans.factory.parsing.ProblemReporter}.  
  14.  */  
  15. public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {  
  16.     //这里取得<bean>中定义的 id name和 aliase的值  
[html] view plain copy
  1. String id = ele.getAttribute(ID_ATTRIBUTE);  
  2. = ele.getAttribute(NAME_ATTRIBUTE);  
[html] view plain copy
  1.         List<String> aliases = new ArrayList<String>();  
  2.         if (StringUtils.hasLength(nameAttr)) {  
  3.             String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);  
  4.             aliases.addAll(Arrays.asList(nameArr));  
  5.         }  
  6.   
  7.         String beanName = id;  
  8.         if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {  
  9.             beanName = aliases.remove(0);  
  10.             if (logger.isDebugEnabled()) {  
  11.                 logger.debug("No XML 'id' specified - using '" + beanName +  
  12.                         "' as bean name and " + aliases + " as aliases");  
  13.             }  
  14.         }  
  15.   
  16.         if (containingBean == null) {  
  17.             checkNameUniqueness(beanName, aliases, ele);  
  18.         }  
  19.                   //这个方法是对bean元素的详细解析  
  20.         <span style="color:#ff0000;">AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);  
  21. </span>     if (beanDefinition != null) {  
  22.             if (!StringUtils.hasText(beanName)) {  
  23.                 try {  
  24.                     if (containingBean != null) {  
  25.                         beanName = BeanDefinitionReaderUtils.generateBeanName(  
  26.                                 beanDefinition, this.readerContext.getRegistry(), true);  
  27.                     }  
  28.                     else {  
  29.                         beanName = this.readerContext.generateBeanName(beanDefinition);  
  30.                         // Register an alias for the plain bean class name, if still possible,  
  31.                         // if the generator returned the class name plus a suffix.  
  32.                         // This is expected for Spring 1.2/2.0 backwards compatibility.  
  33.                         String beanClassName = beanDefinition.getBeanClassName();  
  34.                         if (beanClassName != null &&  
  35.                                 beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&  
  36.                                 !this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {  
  37.                             aliases.add(beanClassName);  
  38.                         }  
  39.                     }  
  40.                     if (logger.isDebugEnabled()) {  
  41.                         logger.debug("Neither XML 'id' nor 'name' specified - " +  
  42.                                 "using generated bean name [" + beanName + "]");  
  43.                     }  
  44.                 }  
  45.                 catch (Exception ex) {  
  46.                     error(ex.getMessage(), ele);  
  47.                     return null;  
  48.                 }  
  49.             }  
  50.             String[] aliasesArray = StringUtils.toStringArray(aliases);  
  51.             return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);  
  52.         }  
  53.   
  54.         return null;  
  55.     }  
看看详细的解析方法: parseBeanDefinitionElement( Element ele, String beanName, BeanDefinition containingBean)
[html] view plain copy
  1. /**  
  2.  * Parse the bean definition itself, without regard to name or aliases. May return  
  3.  * <code>null</code> if problems occurred during the parsing of the bean definition.  
  4.  */  
  5. public AbstractBeanDefinition parseBeanDefinitionElement(  
  6.         Element ele, String beanName, BeanDefinition containingBean) {  
  7.   
  8.     this.parseState.push(new BeanEntry(beanName));  
  9.                  //取得class name的定义,这里指读取<bean>中设置的class的名字,记录到BeanDefinition中,并不涉及对象的实例化过程,实例化实际上是在以来注入的时候完成的  
  10.     String className = null;  
  11.     if (ele.hasAttribute(CLASS_ATTRIBUTE)) {  
  12.         className = ele.getAttribute(CLASS_ATTRIBUTE).trim();  
  13.     }  
  14.   
  15.     try {  
  16.         String parent = null;  
  17.         if (ele.hasAttribute(PARENT_ATTRIBUTE)) {  
  18.             parent = ele.getAttribute(PARENT_ATTRIBUTE);  
  19.         }  
  20.         <span style="color:#ff0000;">AbstractBeanDefinition bd = createBeanDefinition(className, parent);  
  21.                           //对当前的Bean元素进行属性解析,并设置description的信息  
  22. /span>          parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);  
  23.         bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));  
  24.                           //从名字可以看出。这里是对各种<bean>元素的信息进行解析的地方  
  25.         parseMetaElements(ele, bd);  
  26.         parseLookupOverrideSubElements(ele, bd.getMethodOverrides());  
  27.         parseReplacedMethodSubElements(ele, bd.getMethodOverrides());  
  28.                           //解析<bean>的构造函数  
  29.         parseConstructorArgElements(ele, bd);  
  30.         //解析bean的property设置  
[html] view plain copy
  1.                          <span style="color:#ff0000;">parsePropertyElements(ele, bd);  
  2. span>           parseQualifierElements(ele, bd);  
  3.   
  4.     bd.setResource(this.readerContext.getResource());  
  5.     bd.setSource(extractSource(ele));  
  6.   
  7.     return bd;  
  8. }  
  9. catch (ClassNotFoundException ex) {  
  10.     error("Bean class [" + className + "] not found", ele, ex);  
  11. }  
  12. catch (NoClassDefFoundError err) {  
  13.     error("Class that bean class [" + className + "] depends on not found", ele, err);  
  14. }  
  15. catch (Throwable ex) {  
  16.     error("Unexpected failure during bean definition parsing", ele, ex);  
  17. }  
  18. finally {  
  19.     this.parseState.pop();  
  20. }  
  21.   
  22. return null;  

上面主要关注红色的两个方法,一个是创建了BeanDefinition,一个是解析详细的bean的属性设置。

创建BeanDefinition是在调用了类BeanDefinitionReaderUtils.createBeanDefinition(parentName, className, this.readerContext.getBeanClassLoader());方法

[java] view plain copy
  1. /** 
  2.  * Create a new GenericBeanDefinition for the given parent name and class name, 
  3.  * eagerly loading the bean class if a ClassLoader has been specified. 
  4.  * @param parentName the name of the parent bean, if any 
  5.  * @param className the name of the bean class, if any 
  6.  * @param classLoader the ClassLoader to use for loading bean classes 
  7.  * (can be <code>null</code> to just register bean classes by name) 
  8.  * @return the bean definition 
  9.  * @throws ClassNotFoundException if the bean class could not be loaded 
  10.  */  
  11. public static AbstractBeanDefinition createBeanDefinition(  
  12.         String parentName, String className, ClassLoader classLoader) throws ClassNotFoundException {  
  13.   
  14.     GenericBeanDefinition bd = new GenericBeanDefinition();  
  15.     bd.setParentName(parentName);  
  16.     if (className != null) {  
  17.         if (classLoader != null) {  
  18.             bd.setBeanClass(ClassUtils.forName(className, classLoader));  
  19.         }  
  20.         else {  
  21.             bd.setBeanClassName(className);  
  22.         }  
  23.     }  
  24.     return bd;  
  25. }  


再看详细解析bean的属性定义的方法:

 

[html] view plain copy
  1. /**  
  2.  * Parse property sub-elements of the given bean element.  
  3.  */  
  4. public void parsePropertyElements(Element beanEle, BeanDefinition bd) {  
  5.     NodeList nl = beanEle.getChildNodes();  
  6.     for (int i = 0; i < nl.getLength(); i++) {  
  7.         Node node = nl.item(i);  
  8.         if (isCandidateElement(node) && nodeNameEquals(node, PROPERTY_ELEMENT)) {  
  9.             <span style="color:#ff0000;">parsePropertyElement((Element) node, bd);  
  10. /span>          }  
  11.     }  
  12. }  


 

[java] view plain copy
  1. /** 
  2.  * Parse a property element. 
  3.  */  
  4. public void parsePropertyElement(Element ele, BeanDefinition bd) {  
  5.     //取得property的名字  
[java] view plain copy
  1.                 String propertyName = ele.getAttribute(NAME_ATTRIBUTE);  
  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.       //如果在同一个Bean中已经有同名的property存在,则不进行解析,直接返回,也就是说,在同一个bean中的相同property设置,只有第一个起作用  
[java] view plain copy
  1.                       if (bd.getPropertyValues().contains(propertyName)) {  
  2. error("Multiple 'property' definitions for property '" + propertyName + "'", ele);  
  3. return;  
  4.   
  5.                        //这里是解析property的地方,返回的对象对应对bean定义的property属性设置的解析结果,这个解析结果会被封装到PropertyValue中  
[java] view plain copy
  1.     <span style="color:#ff0000;">Object val = parsePropertyValue(ele, bd, propertyName);  
  2. span>           <span style="color:#009900;">PropertyValue pv = new PropertyValue(propertyName, val);  
  3.     parseMetaElements(ele, pv);  
  4.     pv.setSource(extractSource(ele));  
  5.     bd.getPropertyValues().addPropertyValue(pv);  
  6. span>       }  
  7. finally {  
  8.     this.parseState.pop();  
  9. }  
[java] view plain copy
  1.    
[java] view plain copy
  1. 下面这个方法是去的Property元素的值,也许是MAP,LIST SET或者其他ref对象  
[python] view plain copy
  1. /**  
  2.  * Get the value of a property element. May be a list etc.  
  3.  * Also used for constructor arguments, "propertyName" being null in this case.  
  4.  */  
  5. public Object parsePropertyValue(Element ele, BeanDefinition bd, String propertyName) {  
  6.     String elementName = (propertyName != null) ?  
  7.                     "<property> element for property '" + propertyName + "'" :  
  8.                     "<constructor-arg> element";  
  9.   
  10.     // Should only have one child element: ref, value, list, etc.  
  11.     NodeList nl = ele.getChildNodes();  
  12.     Element subElement = null;  
  13.     for (int i = 0; i < nl.getLength(); i++) {  
  14.         Node node = nl.item(i);  
  15.         if (node instanceof Element && !nodeNameEquals(node, DESCRIPTION_ELEMENT) &&  
  16.                 !nodeNameEquals(node, META_ELEMENT)) {  
  17.             // Child element is what we're looking for.  
  18.             if (subElement != null) {  
  19.                 error(elementName + " must not contain more than one sub-element", ele);  
  20.             }  
  21.             else {  
  22.                 subElement = (Element) node;  
  23.             }  
  24.         }  
  25.     }  
  26.                  //这里判断property的属性是ref还是value,不允许同时是ref和value  
  27.     boolean hasRefAttribute = ele.hasAttribute(REF_ATTRIBUTE);  
  28.     boolean hasValueAttribute = ele.hasAttribute(VALUE_ATTRIBUTE);  
  29.     if ((hasRefAttribute && hasValueAttribute) ||  
  30.             ((hasRefAttribute || hasValueAttribute) && subElement != null)) {  
  31.         error(elementName +  
  32.                 " is only allowed to contain either 'ref' attribute OR 'value' attribute OR sub-element", ele);  
  33.     }  
  34.                  //如果是ref,创建一个ref的数据对象RuntimeBeanReference 这个对象封装 了ref的信息  
  35.     if (hasRefAttribute) {  
  36.         String refName = ele.getAttribute(REF_ATTRIBUTE);  
  37.         if (!StringUtils.hasText(refName)) {  
  38.             error(elementName + " contains empty 'ref' attribute", ele);  
  39.         }  
  40.         RuntimeBeanReference ref = new RuntimeBeanReference(refName);  
  41.         ref.setSource(extractSource(ele));  
  42.         return ref;  
  43.     }  
  44.                  //如果是value,创建一个value的数据对象TypeStringValue,这个对象封装了value信息  
[python] view plain copy
  1. else if (hasValueAttribute) {  
  2.     TypedStringValue valueHolder = new TypedStringValue(ele.getAttribute(VALUE_ATTRIBUTE));  
  3.     valueHolder.setSource(extractSource(ele));  
  4.     return valueHolder;  
  5. }  
  6. //如果有子元素,对子元素解析,这里是对Map、List、Set、Property等元素解析  
[python] view plain copy
  1.                 else if (subElement != null) {  
  2.         return parsePropertySubElement(subElement, bd);  
  3.     }  
  4.     else {  
  5.         // Neither child element nor "ref" or "value" attribute found.  
  6.         error(elementName + " must specify a ref or value", ele);  
  7.         return null;  
  8.     }  
  9. }  

上述解析过程可简单的看成是

1、XmlBeanDefinitionReader读取资源,

2、交给DefaultBeanDefinitionDocumentReader对象解析成Document对象,

3、然后DefaultBeanDefinitionDocumentReader对象委托给BeanDefinitionParserDelegate对象解析成BeanDefinitionHoler对象。

4、得到返回的BeanDefunitionHolder对象后调用BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());方法进行注册。

getReaderContext().getRegistry()这里得到的是DefaultListableBeanFactory。在AbstarctXmlApplicationContext的创建XmlBeandefinitionReader的地方可以看到:

[java] view plain copy
  1. XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);  


 

DefaultListableBeanFactory中注册的地方

 

[java] view plain copy
  1. public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)  
  2.         throws BeanDefinitionStoreException {  
  3.   
  4.     Assert.hasText(beanName, "Bean name must not be empty");  
  5.     Assert.notNull(beanDefinition, "BeanDefinition must not be null");  
  6.   
  7.     if (beanDefinition instanceof AbstractBeanDefinition) {  
  8.         try {  
  9.             ((AbstractBeanDefinition) beanDefinition).validate();  
  10.         }  
  11.         catch (BeanDefinitionValidationException ex) {  
  12.             throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,  
  13.                     "Validation of bean definition failed", ex);  
  14.         }  
  15.     }  
  16.                   注册的地方需要同步,保持一致性  
  17.     synchronized (this.beanDefinitionMap) {  
  18.                           //这里检查是不是有相同名字的BeanDefinition已经存在于IOC容器了,如果有相同的名字的BeanDefinition,但又不允许覆盖,会抛出异常  
[java] view plain copy
  1. Object oldBeanDefinition = this.beanDefinitionMap.get(beanName);  
  2. if (oldBeanDefinition != null) {  
  3.     if (!this.allowBeanDefinitionOverriding) {  
  4.         throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,  
  5.                 "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +  
  6.                 "': There is already [" + oldBeanDefinition + "] bound.");  
  7.     }  
  8.     else {  
  9.         if (this.logger.isInfoEnabled()) {  
  10.             this.logger.info("Overriding bean definition for bean '" + beanName +  
  11.                     "': replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]");  
  12.         }  
  13.     }  
  14. }  
  15. else {  
  16.     //这是正常的注册BeanDefinition的过程,把Bean的名字存入到BeanDefinitionNames的同时,beanName作为Map的Key,吧BeanDefinition作为value存入到IOC容器的BeanDefinitionMap中  
[java] view plain copy
  1.                                      this.beanDefinitionNames.add(beanName);  
  2.                 this.frozenBeanDefinitionNames = null;  
  3.             }  
  4.             <span style="color:#ff0000;">this.beanDefinitionMap.put(beanName, beanDefinition);  
  5. </span>     }  
  6.   
  7.         resetBeanDefinition(beanName);  
  8.     }  

上面的代码可以看出IOC容器是作为一个Map实现的。看看DefaultListableBeanFactory中有关容器定义

 

 /** Map from dependency type to corresponding autowired value */
 private final Map<Class<?>, Object> resolvableDependencies = new HashMap<Class<?>, Object>();

 /** 这个就是存放BeanDefinition的容器MAP */
 private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>();

 /** 存放单例的类的名字 */
 private final Map<Class<?>, String[]> singletonBeanNamesByType = new ConcurrentHashMap<Class<?>, String[]>();

 /** Map of non-singleton bean names keyed by bean class */
 private final Map<Class<?>, String[]> nonSingletonBeanNamesByType = new ConcurrentHashMap<Class<?>, String[]>();

 /** 容器中的beanName集合 */
 private final List<String> beanDefinitionNames = new ArrayList<String>();

容器启动时候完成的事情就已经全部分析完成了,类的实例化是在依赖注入或根据配置在容器启动的时候完成的。容器启动加载完成后,就可以再getBean方法调用的时候去使用了。


0 0