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

5分钟快速搭建:使用ros1_bridge实现ROS2容器与ROS1主机的无缝通信 本文详细介绍了如何在5分钟内快速搭建基于ros1_bridge的通信方案,实现运行在Docker容器中的ROS2节点与宿主机ROS1系统的无缝数据交换。通过环境隔离、Docker容器化部署及选择性桥接配置,该方案能有效整合新旧系统,避免大规模代码重构,是机器人项目渐进式升级的实用策略。 阅读详情

   上面讲到,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方法调用的时候去使用了。


Simulink仿真模块 - Data Type Conversion Data Type Conversion将输入信号转换为指定的数据类型 在仿真库中的位置为: Simulink / 常用模块 Simulink / Signal Attributes 模型为: 说明 DataTypeConversion模块可将任何 Simulink®数据类型的输入信号转换为您指定的数据类型。 注意 要通过指定模块参数来控制输出数据类型,或者要从下游模块继承数据类型,使用DataTypeConversion模块。要... 阅读详情

相关推荐

S4HANA - Cost Elements成本要素

SAP这里面的配置逻辑很像,就是先建一个对象,然后不停给这个对象附加一些属性,给一个账户附加编号范围,附加账户组。所有模块的维度都在这个表里,看下图的GL,CO,COPA,AA,ML的都在ACDOCA里。要把这5个类型和六大要素对应,先得把六大要素和账户类型对应下(以下是个人理解,不知道对错):当然那个C是新来的,我觉得放在资产下面也行,就不画图了。S4的嵌入式分析是在业务逻辑都整套嵌入的情况下,预开发了数据模型,所以它能提供的就不仅是原始数据了,它能提供的是包含所有相关联的上下文的信息数据。

weixin_45689053的博客 2393

IOC实现原理

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

sqcwfiu 218

解锁全志T113-i隐藏技能:用RISC-V核跑实时系统比STM32还稳?

本文深入探讨了全志T113-i SoC的异构架构潜力,重点解析如何利用其内置的玄铁C906 RISC-V核心独立运行实时系统。通过对比传统MCU与Linux方案,文章提供了从RISC-V核心启动、FreeRTOS移植到与Linux主核进行高效异构通信的完整实战指南,为工控等需要兼顾丰富应用与硬实时控制的场景提供了高集成度的单芯片解决方案。

ansible6ops的博客 494

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

AI应用架构师:引领半导体良率AI预测的变革浪潮

在半导体行业这个技术密集、资本密集且竞争异常激烈的领域,良率是决定企业盈利能力的关键指标。每提升1%的良率可能意味着数亿美元的利润增长。然而,随着制程节点不断缩小至3nm、2nm甚至更先进水平,传统的良率管理方法已难以应对日益复杂的制造流程和指数级增长的数据量。本文将深入探讨AI应用架构师如何成为这场变革的核心驱动力,通过设计和实施先进的AI预测系统,将半导体良率预测从传统的"事后分析"转变为"事前预测"和"实时优化"。

AI大模型应用之禅 403

Springboot + vue 实现导出word

Springboot + vue 实现导出word 后端代码 使用word先创建好已知的模板 使用word工具另存为.xml格式的文件 使用freemarker ftl模板 将修改后的xml文件复制到开发工具中,将文件后缀修改为ftl文件,并且将里面的动态值使用${}包裹例如:${zyjn} word工具类 /*** * * Project Name:maventest * <p>生成word工具类<br> * * @ClassName: WordUtil *

qq_45542373的博客 2895

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

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

qq_25011427的博客 1043

Aurix TC387 Ethernet代码解析之二_移植

英飞凌官方仅提供了TC397的例程,故需通过TC397例程来移植到TC387新建工程里。TC397官方例程名称【Ethernet_1_KIT_TC397_TFT】,网络上可以免费获取到,此处不赘述。使用工具【

m0_69929716的博客 884

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

RM3100应用笔记驱动程序SPI接口

PNI磁传感器套件RM3100磁传感器套件由2个Sen-XY-f(pn13104)地磁传感器,1个Sen-Z-f(pn13101)地磁传感器和MagI2C(pn13156)控制芯片组成,能够实现三维空间的磁场大小测量。

AIoT技术栈的博客 4923

【机器人学】常用的小车底盘运动学模型推导(附C++代码)

认知有限,望大家多多包涵,有什么问题也希望能够与大家多交流,共同成长!本文先对小车底盘运动学模型介绍做个简单的介绍,具体内容后续再更,其他模块可以参考去我其他文章提示:以下是本篇文章正文内容对于小车的分析,仅仅考虑XY轴的线速度和Z轴的角速度,不考虑和横滚和俯仰的速度,【防盗标记–盒子君hzj】也不考虑Z轴的高度变化【即:车底盘的运动可以用三个独立变量来描述:x轴平动、y轴平动、yaw轴转动】

qq_35635374的博客 1930

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

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

大风的博客 789

hwasan实例分析踩内存之七:CamX进程chifeature2base怪异的Cause: use-after-free

摘要:本文分析了高通camx进程中的指针异常crash问题,通过构建hwasan版本确认存在内存踩踏现象。日志显示为"use-after-free"类型错误,具体为线程T175672在已释放内存区域执行写入操作。堆栈分析表明ChiFeature2Base::PipelineDestroyCb()函数访问了已被ChiFeature2Base::DestroyFeatureData()释放的pPipelineData对象。该问题源于多线程环境下内存管理不同步,导致释放后仍被引用。解决方案通过

1073

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

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

weixin_30555125的博客 166

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

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

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

bugstack虫洞栈 1万+

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

spring ioc实现原理

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

红血哥 2161

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

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

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、付费专栏及课程。

余额充值