分析Spring源代码之 IOC容器的启动 - Go语言中文社区

分析Spring源代码之 IOC容器的启动


(转)菜鸟分析Spring源代码之 IOC容器的启动

20111225 By Tony

1.     前言

6月份开始,我就打算做一个Android下的快速开发架构。详见以下文章:

http://blog.csdn.net/nanjingjiangbiao/article/details/6557150

其中,我曾设想引入Spring来做整体的基础架构。后来发展到,我想研究研究Spring的底层代码。

只可惜项目太忙,只好先花钱买了本计先生的《Spring技术内幕》一书.

好书啊,好书啊,只可惜我看得头晕晕。从头到尾到处是代码,中文理解写的高深莫测,只可惜一个UML图都没有,真是天书啊天书。

怎么办呢?上网看评论,都说看不懂这本书的人都不是好程序员。

没办法,只好自我分析,自我批判Spring源代码。

2.     从Spring的最简单的Sample说起

上网到处都能抄到,以下这种小sample

  1. package com.hyron.tony;  
  2. import org.springframework.beans.factory.BeanFactory;  
  3. import org.springframework.beans.factory.xml.XmlBeanFactory;  
  4. import org.springframework.core.io.ClassPathResource;  
  5.   
  6. public class Test {  
  7.   
  8.     public static void main(String[] args)throws Exception {  
  9.         BeanFactory factory = new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));  
  10.         GreetingService greetingService = (GreetingService)factory.getBean("greetingService");  
  11.         greetingService.sayGreeting();  
  12.     }  
  13.   
  14. }  

以上最起码有两个东西我想搞清,

第一,  XML文件的解析规则和算法在那里

第二,  Object的动态生成在哪里

1.     分析

先上sample的时序图

 

 

 

首先,简单的紧,applicationContext.xml被构造成ClassPathResource对象,代码如下

  1. public ClassPathResource(String path, ClassLoader classLoader) {  
  2.         Assert.notNull(path, "Path must not be null");  
  3.         String pathToUse = StringUtils.cleanPath(path);  
  4.         if (pathToUse.startsWith("/")) {  
  5.             pathToUse = pathToUse.substring(1);  
  6.         }  
  7.         this.path = pathToUse;  
  8.         this.classLoader = (classLoader != null ? classLoader : ClassUtils.getDefaultClassLoader());  
  9.     }  

 

上面完成两个事情,第一是对文件path的编排。第二是,生成一个classloader出来,具体如下:

  1. public static ClassLoader getDefaultClassLoader() {  
  2.         ClassLoader cl = null;  
  3.         try {  
  4.             cl = Thread.currentThread().getContextClassLoader();  
  5.         }  
  6.         catch (Throwable ex) {  
  7.             // Cannot access thread context ClassLoader - falling back to system class loader...  
  8.         }  
  9.         if (cl == null) {  
  10.             // No thread context class loader -> use class loader of this class.  
  11.             cl = ClassUtils.class.getClassLoader();  
  12.         }  
  13.         return cl;  
  14.     }  

 

但是,但是。。。。每一个Resource对象都有一个类加载器的变量??

 

接下来,资源的加载,也就是XML文件的解析,我们在XmlBeanFactory中看到如下代码:

  1. private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);  
  2.   
  3. public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {  
  4.         super(parentBeanFactory);  
  5.         this.reader.loadBeanDefinitions(resource);  
  6.     }  

 

委托啊,委托啊,有木有啊有木有。。

XmlBeanFactory聚合了一个XmlBeanDefinitionReader来处理解析的事情。

然后,我们去XmlBeanDefinitionReader看看XML的解析

代码片段:

  1. //一个HashSet的ThreadLocal变量,用来保证在多线程情况下的数据安全  
  2. //每一个进来的Resource都会被包装进去  
  3. Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();  

 

然后,开始读XML文件咯

代码片段:

  1. //读stream  
  2. InputStream inputStream = encodedResource.getResource().getInputStream();  
  3. //inputstream被包装成JDK的document  
  4. Document doc = this.documentLoader.loadDocument(  
  5.                     inputSource, getEntityResolver(), this.errorHandler, validationMode, isNamespaceAware());  
  6.   
  7. //拿到document的根元素,开始登记  
  8. Element root = doc.getDocumentElement();  
  9. doRegisterBeanDefinitions(root);  

 

下面就所谓的document的登记,这块的代码还是比较有水平的。

代码片段:

  1. //循环Dom树,开始解析  
  2. for (int i = 0; i < nl.getLength(); i++) {  
  3.                 Node node = nl.item(i);  
  4.                 if (node instanceof Element) {  
  5.                     Element ele = (Element) node;  
  6.                     if (delegate.isDefaultNamespace(ele)) {  
  7.                         parseDefaultElement(ele, delegate);  
  8.                     }  
  9.                     else {  
  10.                         delegate.parseCustomElement(ele);  
  11.                     }  
  12.                 }  
  13.             }  
  14.   
  15. //分别为import,alias,bean,beans四种元素做解析  
  16. private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {  
  17.         if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {  
  18.             importBeanDefinitionResource(ele);  
  19.         }  
  20.         else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {  
  21.             processAliasRegistration(ele);  
  22.         }  
  23.         else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {  
  24.             processBeanDefinition(ele, delegate);  
  25.         }  
  26.         else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {  
  27.             // recurse  
  28.             doRegisterBeanDefinitions(ele);  
  29.         }  
  30.     }  
  31.   
  32. //已bean元素为例,真正的解析代码如下  
  33. //将DOM节点的属性都塞入AbstractBeanDefinition对象中  
  34. public AbstractBeanDefinition parseBeanDefinitionAttributes(Element ele, String beanName,  
  35.             BeanDefinition containingBean, AbstractBeanDefinition bd) {  
  36.   
  37.         if (ele.hasAttribute(SCOPE_ATTRIBUTE)) {  
  38.             // Spring 2.x "scope" attribute  
  39.             bd.setScope(ele.getAttribute(SCOPE_ATTRIBUTE));  
  40.             if (ele.hasAttribute(SINGLETON_ATTRIBUTE)) {  
  41.                 error("Specify either 'scope' or 'singleton', not both", ele);  
  42.             }  
  43.         }  
  44.         else if (ele.hasAttribute(SINGLETON_ATTRIBUTE)) {  
  45.             // Spring 1.x "singleton" attribute  
  46.             bd.setScope(TRUE_VALUE.equals(ele.getAttribute(SINGLETON_ATTRIBUTE)) ?  
  47.                     BeanDefinition.SCOPE_SINGLETON : BeanDefinition.SCOPE_PROTOTYPE);  
  48.         }  
  49.         else if (containingBean != null) {  
  50.             // Take default from containing bean in case of an inner bean definition.  
  51.             bd.setScope(containingBean.getScope());  
  52.         }  
  53.   
  54.         if (ele.hasAttribute(ABSTRACT_ATTRIBUTE)) {  
  55.             bd.setAbstract(TRUE_VALUE.equals(ele.getAttribute(ABSTRACT_ATTRIBUTE)));  
  56.         }  
  57.   
  58.         String lazyInit = ele.getAttribute(LAZY_INIT_ATTRIBUTE);  
  59.         if (DEFAULT_VALUE.equals(lazyInit)) {  
  60.             lazyInit = this.defaults.getLazyInit();  
  61.         }  
  62.         bd.setLazyInit(TRUE_VALUE.equals(lazyInit));  
  63.   
  64.         String autowire = ele.getAttribute(AUTOWIRE_ATTRIBUTE);  
  65.         bd.setAutowireMode(getAutowireMode(autowire));  
  66.   
  67.         String dependencyCheck = ele.getAttribute(DEPENDENCY_CHECK_ATTRIBUTE);  
  68.         bd.setDependencyCheck(getDependencyCheck(dependencyCheck));  
  69. 版权声明:本文来源CSDN,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
    原文链接:https://blog.csdn.net/iteye_3829/article/details/82305886
    站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。
    • 发表于 2020-02-25 00:38:01
    • 阅读 ( 1225 )
    • 分类:

0 条评论

请先 登录 后评论

官方社群

GO教程

猜你喜欢