《Spring 技术内幕》深入解析 Spring 架构与设计原理(一)

IOC 的基础  
下面我们从 IOC/AOP 开始,它们是 Spring 平台实现的核心部分;虽然,我们一开始大多只是在这个层面上,做一些配置和外部特性的使用工作,但对这两个核心模块工作原理和运作机制的理解,对深入理解 Spring 平台,却是至关重要的;因为,它们同时也是 Spring 其他模块实现的基础。从 Spring 要做到的目标,也就是从简化 Java EE 开发的出发点来看,简单的来说,它是通过对 POJO 开发的支持,来具体实现的;具体的说,Spring 通过为应用开发提供基于 POJO 的开发模式,把应用开发和复杂的 Java EE 服务,实现解耦,并通过提高单元测试的覆盖率,从而有效的提高整个应用的开发质量。这样一来,实际上,就需要把为 POJO 提供支持的,各种 Java EE 服务支持抽象到应用平台中去,去封装起来;而这种封装功能的实现,在 Spring 中,就是由 IOC 容器以及 AOP 来具体提供的,这两个模块,在很大程度上,体现了 Spring 作为应用开发平台的核心价值。它们的实现,是 Rod.Johnson 在他的另一本著作《Expert One-on-One J2EE Development without EJB》 中,所提到 Without EJB 设计思想的体现;同时也深刻的体现了 Spring 背后的设计理念。  

从更深一点的技术层面上来看,因为 Spring 是一个基于 Java 语言的应用平台,如果我们能够对 Java 计算模型,比如像 JVM 虚拟机实现技术的基本原理有一些了解,会让我们对 Spring 实现的理解,更加的深入,这些 JVM 虚拟机的特性使用,包括像反射机制,代理类,字节码技术等等。它们都是在 Spring 实现中,涉及到的一些 Java 计算环境的底层技术;尽管对应用开发人员来说,可能不会直接去涉及这些 JVM 虚拟机底层实现的工作,但是了解这些背景知识,或多或少,对我们了解整个 Spring 平台的应用背景有很大的帮助;打个比方来说,就像我们在大学中,学习的那些关于计算机组织和系统方面的基本知识,比如像数字电路,计算机组成原理,汇编语言,操作系统等等这些基本课程的学习。虽然,坦率的来说,对我们这些大多数课程的学习者,在以后的工作中,可能并没有太多的机会,直接从事这么如此底层的技术开发工作;但具备这些知识背景,为我们深入理解基于这些基础技术构架起来的应用系统,毫无疑问,是不可缺少的。随着 JVM 虚拟机技术的发展,可以设想到的是,更多虚拟机级别的基本特性,将会持续的被应用平台开发者所关注和采用,这也是我们在学习平台实现的过程中,非常值得注意的一点,因为这些底层技术实现,毫无疑问,会对 Spring 应用平台的开发路线,产品策略产生重大的影响。同时,在使用 Spring 作为应用平台的时候,如果需要更深层次的开发和性能调优,这些底层的知识,也是我们知识库中不可缺少的部分。有了这些底层知识,理解整个系统,想来就应该障碍不大了。  

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

那具体什么是 IoC 容器呢?它在 Spring 框架中到底长什么样?说了这么多,其实对 IoC 容器的使用者来说,我们常常接触到的 BeanFactory 和 ApplicationContext 都可以看成是容器的具体表现形式。这些就是 IoC 容器,或者说在 Spring 中提 IoC 容器,从实现来说,指的是一个容器系列。这也就是说,我们通常所说的 IoC 容器,如果深入到 Spring 的实现去看,会发现 IoC 容器实际上代表着一系列功能各异的容器产品。只是容器的功能有大有小,有各自的特点。打个比方来说,就像是百货商店里出售的商品,我们举水桶为例子,在商店中出售的水桶有大有小;制作材料也各不相同,有金属的,有塑料的等等,总之是各式各样,但只要能装水,具备水桶的基本特性,那就可以作为水桶来出售来让用户使用。这在 Spring 中也是一样,它有各式各样的 IoC 容器的实现供用户选择和使用;使用什么样的容器完全取决于用户的需要,但在使用之前如果能够了解容器的基本情况,那会对容器的使用是非常有帮助的;就像我们在购买商品时进行的对商品的考察和挑选那样。  

我们从最基本的 XmlBeanFactory 看起,它是容器系列的最底层实现,这个容器的实现与我们在 Spring 应用中用到的那些上下文相比,有一个非常明显的特点,它只提供了最基本的 IoC 容器的功能。从它的名字中可以看出,这个 IoC 容器可以读取以 XML 形式定义的 BeanDefinition。理解这一点有助于我们理解 ApplicationContext 与基本的 BeanFactory 之间的区别和联系。我们可以认为直接的 BeanFactory 实现是 IoC 容器的基本形式,而各种 ApplicationContext 的实现是 IoC 容器的高级表现形式。  

仔细阅读 XmlBeanFactory 的源码,在一开始的注释里面已经对 XmlBeanFactory 的功能做了简要的说明,从代码的注释还可以看到,这是 Rod Johnson 在 2001 年就写下的代码,可见这个类应该是 Spring 的元老类了。它是继承 DefaultListableBeanFactory 这个类的,这个 DefaultListableBeanFactory 就是一个很值得注意的容器!  

Java 代码    
  1. public class XmlBeanFactory extends DefaultListableBeanFactory {  
  2.     private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);  
  3.     public XmlBeanFactory(Resource resource) throws BeansException {  
  4.         this(resource, null);  
  5.     }  
  6.     public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {  
  7.         super(parentBeanFactory);  
  8.         this.reader.loadBeanDefinitions(resource);  
  9.     }  
  10. }  

XmlBeanFactory 的功能是建立在 DefaultListableBeanFactory 这个基本容器的基础上的,在这个基本容器的基础上实现了其他诸如 XML 读取的附加功能。对于这些功能的实现原理,看一看 XmlBeanFactory 的代码实现就能很容易地理解。在如下的代码中可以看到,在 XmlBeanFactory 构造方法中需要得到 Resource 对象。对 XmlBeanDefinitionReader 对象的初始化,以及使用这个这个对象来完成 loadBeanDefinitions 的调用,就是这个调用启动了从 Resource 中载入 BeanDefinitions 的过程,这个 loadBeanDefinitions 同时也是 IoC 容器初始化的重要组成部分。  

简单来说,IoC 容器的初始化包括 BeanDefinition 的 Resouce 定位、载入和注册这三个基本的过程。我觉得重点是在载入和对 BeanDefinition 做解析的这个过程。可以从 DefaultListableBeanFactory 来入手看看 IoC 容器是怎样完成 BeanDefinition 载入的。在 refresh 调用完成以后,可以看到 loadDefinition 的调用:  

Java 代码    
  1. public abstract class AbstractXmlApplicationContext extends AbstractRefreshableConfigApplicationContext {  
  2.     public AbstractXmlApplicationContext() {  
  3.     }  
  4.     public AbstractXmlApplicationContext(ApplicationContext parent) {  
  5.         super(parent);  
  6.     }  
  7.     // 这里是实现 loadBeanDefinitions 的地方  
  8.     protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws IOException {  
  9.         // Create a new XmlBeanDefinitionReader for the given BeanFactory.  
  10.         // 创建 XmlBeanDefinitionReader,并通过回调设置到 BeanFactory 中去,创建 BeanFactory 的使用的也是 DefaultListableBeanFactory。  
  11.         XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);  
  12.   
  13.         // Configure the bean definition reader with this context’s  
  14.         // resource loading environment.  
  15.         // 这里设置 XmlBeanDefinitionReader, 为 XmlBeanDefinitionReader 配置 ResourceLoader,因为 DefaultResourceLoader 是父类,所以 this 可以直接被使用  
  16.         beanDefinitionReader.setResourceLoader(this);  
  17.         beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));  
  18.   
  19.         // Allow a subclass to provide custom initialization of the reader,  
  20.         // then proceed with actually loading the bean definitions.  
  21.     // 这是启动 Bean 定义信息载入的过程  
  22.         initBeanDefinitionReader(beanDefinitionReader);  
  23.         loadBeanDefinitions(beanDefinitionReader);  
  24.     }  
  25.   
  26.     protected void initBeanDefinitionReader(XmlBeanDefinitionReader beanDefinitionReader) {  
  27.     }  

这里使用 XmlBeanDefinitionReader 来载入 BeanDefinition 到容器中,如以下代码清单所示:  

Java 代码    
  1.     // 这里是调用的入口。  
  2.     public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {  
  3.         return loadBeanDefinitions(new EncodedResource(resource));  
  4.     }  
  5.     // 这里是载入 XML 形式的 BeanDefinition 的地方。  
  6.     public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {  
  7.         Assert.notNull(encodedResource, “EncodedResource must not be null”);  
  8.         if (logger.isInfoEnabled()) {  
  9.             logger.info(“Loading XML bean definitions from ” + encodedResource.getResource());  
  10.         }  
  11.   
  12.         Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();  
  13.         if (currentResources == null) {  
  14.             currentResources = new HashSet<EncodedResource>(4);  
  15.             this.resourcesCurrentlyBeingLoaded.set(currentResources);  
  16.         }  
  17.         if (!currentResources.add(encodedResource)) {  
  18.             throw new BeanDefinitionStoreException(  
  19.                     “Detected recursive loading of ” + encodedResource + ” – check your import definitions!”);  
  20.         }  
  21.         // 这里得到 XML 文件,并得到 IO 的 InputSource 准备进行读取。  
  22.         try {  
  23.             InputStream inputStream = encodedResource.getResource().getInputStream();  
  24.             try {  
  25.                 InputSource inputSource = new InputSource(inputStream);  
  26.                 if (encodedResource.getEncoding() != null) {  
  27.                     inputSource.setEncoding(encodedResource.getEncoding());  
  28.                 }  
  29.                 return doLoadBeanDefinitions(inputSource, encodedResource.getResource());  
  30.             }  
  31.             finally {  
  32.                 inputStream.close();  
  33.             }  
  34.         }  
  35.         catch (IOException ex) {  
  36.             throw new BeanDefinitionStoreException(  
  37.                     “IOException parsing XML document from ” + encodedResource.getResource(), ex);  
  38.         }  
  39.         finally {  
  40.             currentResources.remove(encodedResource);  
  41.             if (currentResources.isEmpty()) {  
  42.                 this.resourcesCurrentlyBeingLoaded.set(null);  
  43.             }  
  44.         }  
  45.     }  
  46. // 具体的读取过程可以在 doLoadBeanDefinitions 方法中找到:  
  47.     // 这是从特定的 XML 文件中实际载入 BeanDefinition 的地方  
  48.     protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)  
  49.             throws BeanDefinitionStoreException {  
  50.         try {  
  51.             int validationMode = getValidationModeForResource(resource);  
  52.             // 这里取得 XML 文件的 Document 对象,这个解析过程是由 documentLoader 完成的,这个 documentLoader 是 DefaultDocumentLoader, 在定义 documentLoader 的地方创建  
  53.             Document doc = this.documentLoader.loadDocument(  
  54.                     inputSource, getEntityResolver(), this.errorHandler, validationMode, isNamespaceAware());  
  55.             // 这里启动的是对 BeanDefinition 解析的详细过程,这个解析会使用到 Spring 的 Bean 配置规则,是我们下面需要详细关注的地方。  
  56.             return registerBeanDefinitions(doc, resource);  
  57.         }  
  58.         catch (BeanDefinitionStoreException ex) {  
  59.             throw ex;  
  60.         }  
  61.         catch (SAXParseException ex) {  
  62.             throw new XmlBeanDefinitionStoreException(resource.getDescription(),  
  63.                     “Line ” + ex.getLineNumber() + ” in XML document from ” + resource + ” is invalid”, ex);  
  64.         }  
  65.         catch (SAXException ex) {  
  66.             throw new XmlBeanDefinitionStoreException(resource.getDescription(),  
  67.                     “XML document from ” + resource + ” is invalid”, ex);  
  68.         }  
  69.         catch (ParserConfigurationException ex) {  
  70.             throw new BeanDefinitionStoreException(resource.getDescription(),  
  71.                     “Parser configuration exception parsing XML from ” + resource, ex);  
  72.         }  
  73.         catch (IOException ex) {  
  74.             throw new BeanDefinitionStoreException(resource.getDescription(),  
  75.                     “IOException parsing XML document from ” + resource, ex);  
  76.         }  
  77.         catch (Throwable ex) {  
  78.             throw new BeanDefinitionStoreException(resource.getDescription(),  
  79.                     “Unexpected exception parsing XML document from ” + resource, ex);  
  80.         }  
  81.     }  

关于具体的 Spring BeanDefinition 的解析,是在 BeanDefinitionParserDelegate 中完成的。这个类里包含了各种 Spring Bean 定义规则的处理,感兴趣的同学可以仔细研究。我们举一个例子来分析这个处理过程,比如我们最熟悉的对 Bean 元素的处理是怎样完成的,也就是我们在 XML 定义文件中出现的 <bean></bean > 这个最常见的元素信息是怎样被处理的。在这里,我们会看到那些熟悉的 BeanDefinition 定义的处理,比如 id、name、aliase 等属性元素。把这些元素的值从 XML 文件相应的元素的属性中读取出来以后,会被设置到生成的 BeanDefinitionHolder 中去。这些属性的解析还是比较简单的。对于其他元素配置的解析,比如各种 Bean 的属性配置,通过一个较为复杂的解析过程,这个过程是由 parseBeanDefinitionElement 来完成的。解析完成以后,会把解析结果放到 BeanDefinition 对象中并设置到 BeanDefinitionHolder 中去,如以下清单所示:  

Java 代码    
  1. public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {  
  2.         // 这里取得在 <bean> 元素中定义的 id、name 和 aliase 属性的值  
  3.         String id = ele.getAttribute(ID_ATTRIBUTE);  
  4.         String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);  
  5.   
  6.         List<String> aliases = new ArrayList<String>();  
  7.         if (StringUtils.hasLength(nameAttr)) {  
  8.             String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, BEAN_NAME_DELIMITERS);  
  9.             aliases.addAll(Arrays.asList(nameArr));  
  10.         }  
  11.   
  12.         String beanName = id;  
  13.         if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {  
  14.             beanName = aliases.remove(0);  
  15.             if (logger.isDebugEnabled()) {  
  16.                 logger.debug(“No XML ‘id’ specified – using ‘” + beanName +  
  17.                         “‘ as bean name and ” + aliases + ” as aliases”);  
  18.             }  
  19.         }  
  20.   
  21.         if (containingBean == null) {  
  22.             checkNameUniqueness(beanName, aliases, ele);  
  23.         }  
  24.   
  25.         // 这个方法会引发对 bean 元素的详细解析  
  26. AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);  
  27.         if (beanDefinition != null) {  
  28.             if (!StringUtils.hasText(beanName)) {  
  29.                 try {  
  30.                     if (containingBean != null) {  
  31.                         beanName = BeanDefinitionReaderUtils.generateBeanName(  
  32.                                 beanDefinition, this.readerContext.getRegistry(), true);  
  33.                     }  
  34.                     else {  
  35.                         beanName = this.readerContext.generateBeanName(beanDefinition);  
  36.                         // Register an alias for the plain bean class name, if still possible,  
  37.                         // if the generator returned the class name plus a suffix.  
  38.                         // This is expected for Spring 1.2/2.0 backwards compatibility.  
  39.                         String beanClassName = beanDefinition.getBeanClassName();  
  40.                         if (beanClassName != null &&  
  41.                                 beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&  
  42.                                 !this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {  
  43.                             aliases.add(beanClassName);  
  44.                         }  
  45.                     }  
  46.                     if (logger.isDebugEnabled()) {  
  47.                         logger.debug(“Neither XML ‘id’ nor ‘name’ specified – ” +  
  48.                                 “using generated bean name [” + beanName + “]”);  
  49.                     }  
  50.                 }  
  51.                 catch (Exception ex) {  
  52.                     error(ex.getMessage(), ele);  
  53.                     return null;  
  54.                 }  
  55.             }  
  56.             String[] aliasesArray = StringUtils.toStringArray(aliases);  
  57.             return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);  
  58.         }  
  59.   
  60.         return null;  
  61.     }  

在具体生成 BeanDefinition 以后。我们举一个对 property 进行解析的例子来完成对整个 BeanDefinition 载入过程的分析,还是在类 BeanDefinitionParserDelegate 的代码中,它对 BeanDefinition 中的定义一层一层地进行解析,比如从属性元素集合到具体的每一个属性元素,然后才是对具体的属性值的处理。根据解析结果,对这些属性值的处理会封装成 PropertyValue 对象并设置到 BeanDefinition 对象中去,如以下代码清单所示。  

Java 代码    
  1. /** 
  2.  * 这里对指定 bean 元素的 property 子元素集合进行解析。 
  3.  */  
  4. public void parsePropertyElements(Element beanEle, BeanDefinition bd) {  
  5.     // 遍历所有 bean 元素下定义的 property 元素  
  6.     NodeList nl = beanEle.getChildNodes();  
  7.     for (int i = 0; i < nl.getLength(); i++) {  
  8.         Node node = nl.item(i);  
  9.         if (node instanceof Element && DomUtils.nodeNameEquals(node, PROPERTY_ELEMENT)) {  
  10.             // 在判断是 property 元素后对该 property 元素进行解析的过程  
  11.             parsePropertyElement((Element) node, bd);  
  12.         }  
  13.     }  
  14. }  
  15. public void parsePropertyElement(Element ele, BeanDefinition bd) {  
  16.     // 这里取得 property 的名字  
  17.     String propertyName = ele.getAttribute(NAME_ATTRIBUTE);  
  18.     if (!StringUtils.hasLength(propertyName)) {  
  19.         error(“Tag ‘property’ must have a ‘name’ attribute”, ele);  
  20.         return;  
  21.     }  
  22.     this.parseState.push(new PropertyEntry(propertyName));  
  23.     try {  
  24.         // 如果同一个 bean 中已经有同名的存在,则不进行解析,直接返回。也就是说,如果在同一个 bean 中有同名的 property 设置,那么起作用的只是第一个。  
  25.         if (bd.getPropertyValues().contains(propertyName)) {  
  26.             error(“Multiple ‘property’ definitions for property ‘” + propertyName + “‘”, ele);  
  27.             return;  
  28.         }  
  29.         // 这里是解析 property 值的地方,返回的对象对应对 Bean 定义的 property 属性设置的解析结果,这个解析结果会封装到 PropertyValue 对象中,然后设置到 BeanDefinitionHolder 中去。  
  30.         Object val = parsePropertyValue(ele, bd, propertyName);  
  31.         PropertyValue pv = new PropertyValue(propertyName, val);  
  32.         parseMetaElements(ele, pv);  
  33.         pv.setSource(extractSource(ele));  
  34.         bd.getPropertyValues().addPropertyValue(pv);  
  35.     }  
  36.     finally {  
  37.         this.parseState.pop();  
  38.     }  
  39. }  
  40. /** 
  41.  * 这里取得 property 元素的值,也许是一个 list 或其他。 
  42.  */  
  43. public Object parsePropertyValue(Element ele, BeanDefinition bd, String propertyName) {  
  44.     String elementName = (propertyName != null) ?  
  45.                     “<property> element for property ‘” + propertyName + “‘” :  
  46.                     “<constructor-arg> element”;  
  47.   
  48.     // Should only have one child element: ref, value, list, etc.  
  49.     NodeList nl = ele.getChildNodes();  
  50.     Element subElement = null;  
  51.     for (int i = 0; i < nl.getLength(); i++) {  
  52.         Node node = nl.item(i);  
  53.         if (node instanceof Element && !DomUtils.nodeNameEquals(node, DESCRIPTION_ELEMENT) &&  
  54.                 !DomUtils.nodeNameEquals(node, META_ELEMENT)) {  
  55.             // Child element is what we’re looking for.  
  56.             if (subElement != null) {  
  57.                 error(elementName + ” must not contain more than one sub-element”, ele);  
  58.             }  
  59.             else {  
  60.                 subElement = (Element) node;  
  61.             }  
  62.         }  
  63.     }  
  64.     // 这里判断 property 的属性,是 ref 还是 value, 不允许同时是 ref 和 value。  
  65.     boolean hasRefAttribute = ele.hasAttribute(REF_ATTRIBUTE);  
  66.     boolean hasValueAttribute = ele.hasAttribute(VALUE_ATTRIBUTE);  
  67.     if ((hasRefAttribute && hasValueAttribute) ||  
  68.             ((hasRefAttribute || hasValueAttribute) && subElement != null)) {  
  69.         error(elementName +  
  70.                 ” is only allowed to contain either ‘ref’ attribute OR ‘value’ attribute OR sub-element”, ele);  
  71.     }  
  72.     // 如果是 ref,创建一个 ref 的数据对象 RuntimeBeanReference, 这个对象封装了 ref 的信息。  
  73.     if (hasRefAttribute) {  
  74.         String refName = ele.getAttribute(REF_ATTRIBUTE);  
  75.         if (!StringUtils.hasText(refName)) {  
  76.             error(elementName + ” contains empty ‘ref’ attribute”, ele);  
  77.         }  
  78.         RuntimeBeanReference ref = new RuntimeBeanReference(refName);  
  79.         ref.setSource(extractSource(ele));  
  80.         return ref;  
  81.     } // 如果是 value,创建一个 value 的数据对象 TypedStringValue , 这个对象封装了 value 的信息。  
  82.     else if (hasValueAttribute) {  
  83.         TypedStringValue valueHolder = new TypedStringValue(ele.getAttribute(VALUE_ATTRIBUTE));  
  84.         valueHolder.setSource(extractSource(ele));  
  85.         return valueHolder;  
  86.     } // 如果还有子元素,触发对子元素的解析  
  87.     else if (subElement != null) {  
  88.         return parsePropertySubElement(subElement, bd);  
  89.     }  
  90.     else {  
  91.         // Neither child element nor “ref” or “value” attribute found.  
  92.         error(elementName + ” must specify a ref or value”, ele);  
  93.         return null;  
  94.     }  
  95. }  

比如,再往下看,我们看到像 List 这样的属性配置是怎样被解析的,依然在 BeanDefinitionParserDelegate 中:返回的是一个 List 对象,这个 List 是 Spring 定义的 ManagedList,作为封装 List 这类配置定义的数据封装,如以下代码清单所示。  

Java 代码    
  1. public List parseListElement(Element collectionEle, BeanDefinition bd) {  
  2.     String defaultElementType = collectionEle.getAttribute(VALUE_TYPE_ATTRIBUTE);  
  3.     NodeList nl = collectionEle.getChildNodes();  
  4.     ManagedList<Object> target = new ManagedList<Object>(nl.getLength());  
  5.     target.setSource(extractSource(collectionEle));  
  6.     target.setElementTypeName(defaultElementType);  
  7.     target.setMergeEnabled(parseMergeAttribute(collectionEle));  
  8.     // 具体的 List 元素的解析过程。  
  9.     parseCollectionElements(nl, target, bd, defaultElementType);  
  10.     return target;  
  11. }  
  12. protected void parseCollectionElements(  
  13.         NodeList elementNodes, Collection<Object> target, BeanDefinition bd, String defaultElementType) {  
  14.     // 遍历所有的元素节点,并判断其类型是否为 Element。  
  15.     for (int i = 0; i < elementNodes.getLength(); i++) {  
  16.         Node node = elementNodes.item(i);  
  17.         if (node instanceof Element && !DomUtils.nodeNameEquals(node, DESCRIPTION_ELEMENT)) {  
  18.     // 加入到 target 中去,target 是一个 ManagedList,同时触发对下一层子元素的解析过程,这是一个递归的调用。  
  19.             target.add(parsePropertySubElement((Element) node, bd, defaultElementType));  
  20.         }  
  21.     }  
  22. }  

经过这样一层一层的解析,我们在 XML 文件中定义的 BeanDefinition 就被整个给载入到了 IoC 容器中,并在容器中建立了数据映射。在 IoC 容器中建立了对应的数据结构,或者说可以看成是 POJO 对象在 IoC 容器中的映像,这些数据结构可以以 AbstractBeanDefinition 为入口,让 IoC 容器执行索引、查询和操作。  

在我的感觉中,对核心数据结构的定义和处理应该可以看成是一个软件的核心部分了。所以,这里的 BeanDefinition 的载入可以说是 IoC 容器的核心,如果说 IoC 容器是 Spring 的核心,那么这些 BeanDefinition 就是 Spring 的核心的核心了!  

呵呵,这部分代码数量不小,但如果掌握这条主线,其他都可以举一反三吧,就像我们掌握了操作系统启动的过程,以及在操作系统设计中的核心数据结构像进程数据结构,文件系统数据结构,网络协议数据结构的设计和处理一样,对整个系统的设计原理,包括移植,驱动开发和应用开发,是非常有帮助的!

© 版权声明
THE END
喜欢就支持一下吧
点赞10 分享
评论 共1条
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片