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

本文详细剖析了Spring框架中IOC容器的启动过程,包括XML配置文件的解析规则、Bean对象的动态生成机制等内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

20111225 By Tony

1.     前言

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

http://blog.youkuaiyun.com/nanjingjiangbiao/article/details/6557150

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

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

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

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

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

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

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

[java]  view plain copy print ?
  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对象,代码如下

[java]  view plain copy print ?
  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出来,具体如下:

[java]  view plain copy print ?
  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中看到如下代码:

[java]  view plain copy print ?
  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的解析

代码片段:

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

 

然后,开始读XML文件咯

代码片段:

[java]  view plain copy print ?
  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的登记,这块的代码还是比较有水平的。

代码片段:

[java]  view plain copy print ?
  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.   
  70.         if (ele.hasAttribute(DEPENDS_ON_ATTRIBUTE)) {  
  71.             String dependsOn = ele.getAttribute(DEPENDS_ON_ATTRIBUTE);  
  72.             bd.setDependsOn(StringUtils.tokenizeToStringArray(dependsOn, MULTI_VALUE_ATTRIBUTE_DELIMITERS));  
  73.         }  
  74.   
  75.         String autowireCandidate = ele.getAttribute(AUTOWIRE_CANDIDATE_ATTRIBUTE);  
  76.         if ("".equals(autowireCandidate) || DEFAULT_VALUE.equals(autowireCandidate)) {  
  77.             String candidatePattern = this.defaults.getAutowireCandidates();  
  78.             if (candidatePattern != null) {  
  79.                 String[] patterns = StringUtils.commaDelimitedListToStringArray(candidatePattern);  
  80.                 bd.setAutowireCandidate(PatternMatchUtils.simpleMatch(patterns, beanName));  
  81.             }  
  82.         }  
  83.         else {  
  84.             bd.setAutowireCandidate(TRUE_VALUE.equals(autowireCandidate));  
  85.         }  
  86.   
  87.         if (ele.hasAttribute(PRIMARY_ATTRIBUTE)) {  
  88.             bd.setPrimary(TRUE_VALUE.equals(ele.getAttribute(PRIMARY_ATTRIBUTE)));  
  89.         }  
  90.   
  91.         if (ele.hasAttribute(INIT_METHOD_ATTRIBUTE)) {  
  92.             String initMethodName = ele.getAttribute(INIT_METHOD_ATTRIBUTE);  
  93.             if (!"".equals(initMethodName)) {  
  94.                 bd.setInitMethodName(initMethodName);  
  95.             }  
  96.         }  
  97.         else {  
  98.             if (this.defaults.getInitMethod() != null) {  
  99.                 bd.setInitMethodName(this.defaults.getInitMethod());  
  100.                 bd.setEnforceInitMethod(false);  
  101.             }  
  102.         }  
  103.   
  104.         if (ele.hasAttribute(DESTROY_METHOD_ATTRIBUTE)) {  
  105.             String destroyMethodName = ele.getAttribute(DESTROY_METHOD_ATTRIBUTE);  
  106.             if (!"".equals(destroyMethodName)) {  
  107.                 bd.setDestroyMethodName(destroyMethodName);  
  108.             }  
  109.         }  
  110.         else {  
  111.             if (this.defaults.getDestroyMethod() != null) {  
  112.                 bd.setDestroyMethodName(this.defaults.getDestroyMethod());  
  113.                 bd.setEnforceDestroyMethod(false);  
  114.             }  
  115.         }  
  116.   
  117.         if (ele.hasAttribute(FACTORY_METHOD_ATTRIBUTE)) {  
  118.             bd.setFactoryMethodName(ele.getAttribute(FACTORY_METHOD_ATTRIBUTE));  
  119.         }  
  120.         if (ele.hasAttribute(FACTORY_BEAN_ATTRIBUTE)) {  
  121.             bd.setFactoryBeanName(ele.getAttribute(FACTORY_BEAN_ATTRIBUTE));  
  122.         }  
  123.   
  124.         return bd;  
  125.     }  
  126.   
  127. //最后,在bean容器中注册BeanDefiniton  
  128. //这里所谓的bean容器就是XmlBeanFactory在构造的时候,塞入的DefaultListableBeanFactory  
  129. //其中,储存用的数据结构是个线程安全的ConcurrentHashMap  
  130. synchronized (this.beanDefinitionMap) {  
  131.             Object oldBeanDefinition = this.beanDefinitionMap.get(beanName);  
  132.             if (oldBeanDefinition != null) {  
  133.                 if (!this.allowBeanDefinitionOverriding) {  
  134.                     throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,  
  135.                             "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +  
  136.                             "': There is already [" + oldBeanDefinition + "] bound.");  
  137.                 }  
  138.                 else {  
  139.                     if (this.logger.isInfoEnabled()) {  
  140.                         this.logger.info("Overriding bean definition for bean '" + beanName +  
  141.                                 "': replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]");  
  142.                     }  
  143.                 }  
  144.             }  
  145.             else {  
  146.                 this.beanDefinitionNames.add(beanName);  
  147.                 this.frozenBeanDefinitionNames = null;  
  148.             }  
  149.             this.beanDefinitionMap.put(beanName, beanDefinition);  
  150.   
  151.             resetBeanDefinition(beanName);  
  152.         }  

 

。。。至于Bean的生成,下次再说吧,累了,去吃饭去了。。。

Bean的生成,中间有关于单例,线程安全,性能,缓存,都会是比较有意思的问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值