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

Frenet坐标系下动态街道场景的最优轨迹生成 本文详细解读了Lattice Planner 阅读详情

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

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

  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)方法:

 

  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)方法:

  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)方法,此方法调用了下面的方法

  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方法:

  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类中的解析方法,

  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的值  
  1. String id = ele.getAttribute(ID_ATTRIBUTE);  
  2. = ele.getAttribute(NAME_ATTRIBUTE);  
  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)
  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设置  
  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());方法

  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的属性定义的方法:

 

  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. }  


 

  1. /** 
  2.  * Parse a property element. 
  3.  */  
  4. public void parsePropertyElement(Element ele, BeanDefinition bd) {  
  5.     //取得property的名字  
  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设置,只有第一个起作用  
  1.                       if (bd.getPropertyValues().contains(propertyName)) {  
  2. error("Multiple 'property' definitions for property '" + propertyName + "'", ele);  
  3. return;  
  4.   
  5.                        //这里是解析property的地方,返回的对象对应对bean定义的property属性设置的解析结果,这个解析结果会被封装到PropertyValue中  
  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. }  
  1.    
  1. 下面这个方法是去的Property元素的值,也许是MAP,LIST SET或者其他ref对象  
  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信息  
  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等元素解析  
  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的地方可以看到:

  1. XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);  


 

DefaultListableBeanFactory中注册的地方

 

  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,但又不允许覆盖,会抛出异常  
  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中  
  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方法调用的时候去使用了。


uniapp [微信小程序] - 详解微信小程序端接入mqtt全流程及示例源码教程,uniApp微信小程序端如何接入MQTT插件并实现连接/断开+发布订阅+消息队列+离线重连等各种示例代码(开箱即用) uniapp微信小程序接入MQTT,uniapp中使用mqtt,uniapp 微信小程序端接入mqtt示例代码教程,适用于微信小程序的MQTT插件,uniapp开发微信小程序连接mqtt,uniApp微信小程序接入MQTT协议,uniapp vue3微信小程序使用MQTT的小例子接入流程,使用uniapp开发小程序接入mqtt,如何在uniapp项目中使用mqtt,uniapp mqtt的使用示例,mqtt连接报错,如何在项目里集成mqtt,Mqtt协议,主动连接mqtt,订阅消息,实现发布,订阅和接收消息 阅读详情

相关推荐

发那科机器人抓手与物料搬运阀的配置与优化实践

本文详细介绍了发那科机器人抓手与物料搬运阀的配置与优化实践,包括基础配置指南、阀岛与输入模块的详细设置、测试程序编写与验证技巧,以及常见问题排查与性能优化建议。通过实际案例和经验分享,帮助技术人员快速掌握关键配置步骤,提升物料搬运系统的稳定性和效率。

weixin_33738555的博客 382

IOC实现原理

对Spring IOC的理解离不开对依赖反转模式的理解,我们知道,关于如何反转对依赖的控制,把控制权从具体业务对象手中转交到平台或者框架中,是解决面向对象系统设计复杂性和提高面向对象系统可测试性的一个有效的解决方案。这个问题触发了IoC设计模式的发展,是IoC容器要解决的核心问题。同时,也是产品化的IoC容器出现的推动力。而我觉得Spring的IoC容器,就是一个开源的实现依赖反转模式的产品。 ...

sqcwfiu 218

自定义串口通讯协议

自定义串口通讯协议的实现方法

qq_44826038的博客 2172

3.7 spring-property 子元素的使用与解析

1.0 Property子元素的使用   property 子元素是再常用不过的了, 在看Spring源码之前,我们先看看它的使用方法, 1. 实例类如下: 1 public class Animal { 2 3 public String type; 4 5 public Set&lt;Integer&gt; age; 6 7 p...

weixin_34387284的博客 229

用51单片机和LD3320语音模块DIY一个会说话的温度报警器(附完整代码)

本文详细介绍了如何使用51单片机和LD3320语音模块DIY一个智能温度报警器,包括硬件选型、电路设计、软件开发及核心功能实现。通过DS18B20温度传感器和语音模块的结合,实现温度超标时的语音报警功能,适合智能家居系统等应用场景。附完整代码,方便开发者快速复现。

weixin_42525632的博客 419

【机器学习】Anaconda安装后打不开jupyter notebook(网页不自动跳出)

anaconda安装成功以后,jupyter notebook可以出现打开的路径,能够手动复制粘贴地址路径打开,却不能自动跳转到网页。解决的办法是在配置文件中加入指定的浏览器配置信息。

weixin_43416960的博客 4万+

Spring源码解析(2)之默认标签的解析(二)

首先感谢 《Spring源码深度解析》郝佳,让我对spring源码有了更深的理解,本篇文章主要是对《Spring源码深度解析》解读的笔记以及自己对书本解读后的理解,本篇文章是对上面一篇Spring源码解析(2)之默认标签的解析(一)的衔接。 ⑥:解析子元素constructor-arg       constructor-arg的使用: &lt;bean id="car" class="zhu...

qq_25011427的博客 1043

Windows 下 Codex MCP 服务配置全攻略:从环境搭建到实战避坑

本文详细介绍了在Windows系统下配置Codex MCP服务的完整流程与实战避坑指南。内容涵盖从Node.js环境搭建、Codex CLI安装,到核心配置文件config.toml的编写与解析,并重点解决了Windows平台特有的环境变量设置、MCP服务启动命令适配等关键难点,帮助开发者顺利完成从环境准备到编辑器插件连接的整个配置过程。

weixin_28826545的博客 2066

12、【死磕 Spring】—— IoC 之解析 <bean> 标签:constructor-arg、property、qualifier(转译)

上篇博客《【死磕 Spring】—— IoC 之解析标签:meta、lookup-method、replace-method》分析了meta、lookup-method、replace-method三个子元素。这篇博客,我们来分析constructor-arg、property、<qualifier>三个子元素。 1. constructor-arg 子元素 1.1 ...

a1290123825的博客 398

双传声器法测量吸声材料的吸声系数(公式推导与解释)

在双传声器法中,通过测量两个位置的声压 p1和 p2​,可以分离出入射波和反射波的声压分量。双传声器法一般在阻抗管中进行,阻抗管的一端为平面波声源,另一端放置待测材料。两个传声器放置在靠近材料的阻抗管内,用于测量管道内的声压。双传声器法是一种常用于测量材料吸声系数的实验方法,通过在管道内使用两个传声器测量声波的入射和反射,来计算出材料的吸声系数。当测试样品较少时,测试时,需要交换两个传声器的位置,目的是为了相位校准。

m0_57407372的博客 1875

三、Crowd与JIRA、Confluence用户集成并SSO单点登录

补充说明: 通过此方法集成后,用户、组以及用户和组的关系都在Crowd系统中存储,但各个系统的权限仍由各系统控制,也可在JIRA和Confluence中添加和删除用户。 在做步骤4和步骤5的时候,要特别小心,确保当前系统的超级权限用户(一般为admin,具体看当前系统的全局权限配置)和组以及它们的关系已经在Crowd中同样存在了,才可切换并禁用当前系统的内部用户目录,否则可能造成权限丢失等严重问题(因为禁用了内部用户目录,而Crowd中又不存在这个超级权限用户和组或它们的关系,所以权限就丢失了) 维护示例

weixin_38621072的博客 2984

spring学习(三)——BeanDefinition的拼装(标签解析:bean补充)

参考文章: http://www.iocoder.cn 上文太长了,截断补充 构造函数解析 parseConstructorArgElements/parseConstructorArgElement 完成 constructor-arg 子元素的解析 【这里是代码】 public void parseConstructorArgElements(Element bea...

大风的博客 789

混响效果的编程实现:Schroeder混响模型与Moorer型混响

Schroeder混响模型是由Manfred R. Schroeder在1962年提出的,它基于一系列串联的反射器(Allpass Comb Filters)和并联的反射器(Feedback Comb Filters)构成。Schroeder混响模型是由Manfred R. Schroeder在1962年提出的,它基于一系列串联的反射器(Allpass Comb Filters)和并联的反射器(Feedback Comb Filters)构成。通过调整各个反射器和全通滤波器的参数,可以实现不同的混响效果。

2301_79326857的博客 1081

spring源码之IOC容器资源载入和注册

铺垫 从上一篇文章我们已经了解到了spring IoC容器的在初始化容器时,对初始化资源的定位过程,即以FileSystem方式存在的Resource的定位问题,在BeanDefinition资源定位完成的基础上,就可以通过返回的Resource对象来进行BeanDefinition的载入了,在定位完成以后,为后面的BeanDefinition的载入创造了I/O操作的条件。就相当于我们...

weixin_30555125的博客 166

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

CRUD搬砖两三年了,怎么阅读Spring源码?

作者:小傅哥 博客:https://bugstack.cn 沉淀、分享、成长,让自己和他人都能有所收获!???? ????‍????连读同事写的代码都费劲,还读Spring? 咋的,Spring 很难读! 这个与我们码农朝夕相处的 Spring,就像睡在你身边的媳妇,你知道找她要吃、要喝、要零花钱、要买皮肤。但你不知道她的仓库共有多少存粮、也不知道她是买了理财还是存了银行。????开个玩笑,接下来我要正经了! 一、为什么Spring难读懂? 为什么 Spring 天天用,但要想去读一读源码,怎么就那

bugstack虫洞栈 1万+

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

spring ioc实现原理

特性Spring IoC 实现控制反转将对象创建交给容器管理依赖注入支持字段、构造器、Setter 注入Bean 生命周期完整的初始化、销毁流程循环依赖使用三级缓存机制解决单例 Bean 循环依赖扩展机制提供多种扩展点(BeanFactoryPostProcessor、BeanPostProcessor)

红血哥 2161

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

Spring 源码解析 - Bean资源加载注册过程

的使用情况,可以发现在容器关闭时也对其进行了上锁,主要就是为了防止放生冲突,在锁中可以看到又触发了很多方法,逻辑比较多,这里主要看。对象时会对已经初始化好的对象进行记录,因此这里可以用来判断容器是否初始化完成,如果容器已经初始化,则为了避免数据的不统一,这里对。中的命名空间是否是默认的还是自定义的,如果是自定义的则使用用户自定义的解析规则,否则使用默认的解析,由于前面例子中的。去容器中获取,如果容器中存在,并不允许覆盖,则抛出异常,还会判断容器中的。方法中,在该方法中,将读取资源文件为输入流,然后使用。

小毕超博客 907

Spring IOC容器的源码阅读,通过一张思维导图把Spring IOC都总结好了

一、前言 作为一个经常使用 Spring 的后端程序员,很早就想彻底弄懂整个 Spring 框架了!但它整体是非常大的. spring ioc 思维导图:点击领取spring全套视频与源码:暗号优快云 最新2020整理收集的一线互联网公司面试真题(都整理成文档),有很多干货,包含netty,spring,线程,spring cloud等详细讲解,也有详细的学习规划图,面试题整理等,我感觉在面试这块讲的非常清楚:获取面试资料只需:点击这里领取!!! 暗号:优快云 二、文章将围绕什么来进行展开? 不多,就一

a3961401的博客 6533

Spring进阶- Spring IOC实现原理(二)IOC初始化流程

AbstractBeanDefinitionReader的loadBeanDefinitions方法源码如下:这个类并不是加载 xml 的过程,它是创建了一个 Resource 对象,分派 Resource 对象给子类来加载 Bean.@Override// 模式匹配类型的解析器,这种方式是加载多个满足匹配条件的资源try {// 获取到要加载的资源// 委派调用其子类XmlBeanDefinitionReader的方法,实现加载功能= null) {else {

CoFFee________的博客 1229

Spring IOC源码实现

摘要:本文详细解析了Spring IOC容器的实现原理与源码结构。主要内容包括:1)Spring IOC核心流程:资源定位、Bean定义解析与注册、实例化、初始化和使用;2)核心类介绍(BeanFactory、ApplicationContext等);3)简化版IOC容器实现示例;4)源码阅读入口建议(DefaultListableBeanFactory等);5)深入讲解BeanDefinition注册、依赖注入、生命周期管理等核心机制,并提供了构造器注入的简化实现代码。

onlymscn的博客 799

【Spring】Spring ioc源码学习以及关于阅读源码方式的一些小笔记

spring源码阅读笔记

要继续努力的孤独的博客 390

Java面试复习总结(Spring篇3)——Spring IOC容器的加载过程

目录 spring ioc 容器的加载流程 Spring Ioc Demo ApplicationContext 继承结构 Spring Ioc容器加载过程源码详解 refresh()方法 调试栈截图 整体流程 bean.xml的处理 loadBeanDefinitions loadBeanDefinitions: 源码阅读 loadBeanDefinitions s...

Slayer_Zhao的博客 1830

Spring IOC 源码解析(七) BeanDefinition 的注册

一.项目准备 1.1 创建项目 首先创建一个简单的 maven 项目,并导入 spring 最基础的依赖包. 这里用到的 spring 版本是 5.1.3.RELEASE 因为我们只用到最简单 BeanFactory ,并没有用 ApplicationContext (高级封装的 BeanFactory),所以只要一个 spring-beans 的依赖即可 &amp;amp;lt;dependencie...

Carey丶zsh 的博客 450

spring源码之IOC容器资源定位过程

铺垫 平时我们在使用spring进行项目实践的时候,对于底层的某些实现逻辑大部分都被忽略过,但是对底层实现的了解却往往是我们在实践中解决出现问题最有利的帮助。以下是我阅读源码进行并整理的一些学习笔记。准备工作 在开发环境中构建自己的spring源码环境,本人是使用IDEA开发工具,构建步骤网上一搜一大把,下面就附上一个在IDEA搭建spring源码环境的链接: ...

weixin_33877885的博客 123

Spring源码解析之IOC篇

文章目录学习重点什么是IOC?准备工作第一步:配置元数据第二步:配置解析第三步:关键类IOC的初始化(从无到有)基于XML的IOC容器的初始化1.定位2.加载3.注册基于Annotation的IOC容器的初始化1.入口2.直接解析配置注解的类3.扫描指定包路径下的所有类总结 学习重点 不要想着背!不要想着背!不要想着背!:顺着流程和思路逐步理解。 知行合一!知行合一!知行合一!:学完每个阶段性知识,一定要文档输出或实践。 OK,说完重点,我们开始! 什么是IOC? IOC(Inversion Of Cont

NightWish- 的博客 674

死磕spring源码五遍,十遍--解析注册

spring很是重要,所以就是干! 阅读spring源码的时候这三个模块尤其中要,因为是初学,所以 首先重点关注这三个模块 接下来就是开始搭建阅读spring源码的环境在idea 中用maven直接在github拉取 https://github.com/spring-projects/spring-framework 然后在idea terminal预编译直接下面的命令 ./gr...

qq_35306443的博客 920
上一篇: Spring IOC 源码阅读之资源定位加载
下一篇: Mybatis深入了解(五)----动态SQL
Footloose_
博客等级 码龄10年 254粉丝 11原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值