`
aijuans
  • 浏览: 1558244 次
社区版块
存档分类
最新评论

分析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.   
  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的生成,中间有关于单例,线程安全,性能,缓存,都会是比较有意思的问题。

分享到:
评论

相关推荐

    Spring源代码解析(一):IOC容器.doc

    在Spring源代码解析的第一部分,我们将聚焦于IOC容器,特别是BeanFactory接口,它是所有Spring容器的基础。 BeanFactory接口是Spring的基石,它定义了基本的容器操作,如获取Bean、检查Bean是否存在、确定Bean的...

    Spring源代码解析

    Spring源代码解析(二):IoC容器在Web容器中的启动 Spring源代码解析(三):Spring JDBC Spring源代码解析(四):Spring MVC Spring源代码解析(五):Spring AOP获取Proxy Spring源代码解析(六):Spring声明式事务...

    Spring源代码解析(二):IoC容器在Web容器中的启动.doc

    当我们在Web环境中运行Spring应用时,IoC容器需要在Web容器(如Tomcat、Jetty等)中启动并运行。这个过程涉及到一系列的初始化步骤,确保Spring能够正确地与Web容器集成。 首先,`WebApplicationContext`是`...

    Spring源代码解析.rar

    Spring源代码解析2:IoC容器在Web容器中的启动.doc Spring源代码解析3:Spring JDBC .doc Spring源代码解析4:Spring MVC .doc Spring源代码解析5:Spring AOP获取Proxy .doc Spring源代码解析6:Spring声明式事务...

    Spring 源代码解析

    Spring源代码解析2:IoC容器在Web容器中的启动;Spring源代码解析3:Spring JDBC ; Spring源代码解析4:Spring MVC ;Spring源代码解析5:Spring AOP获取Proxy;Spring源代码解析6:Spring声明式事务处理 ; ...

    Spring2.5.6源代码分析(一):IOC容器

    本文将通过分析Spring源代码来揭示其IoC容器的工作原理。 首先,我们要理解IoC的概念。IoC是一种设计模式,它将对象的创建和管理从应用逻辑中解耦出来,由一个中心组件(如Spring的ApplicationContext)负责。在...

    SpringIOC示例源代码

    3. `TestIoC.java`:这是一个关于IoC容器的测试类,它可能使用Spring的ApplicationContext接口来加载bean.xml配置,然后通过容器获取并测试bean实例。 4. `ServiceBean.java`:这可能是一个通用的服务bean,用于...

    spring源代码解析

    2. **Web环境下的IOC容器启动**:"spring源代码解析(二):IOC容器在web中启动.doc"涵盖了在Web应用中初始化Spring容器的过程,包括ApplicationContext的创建、DispatcherServlet的配置以及如何在Web环境中注入bean...

    山寨spring_ ioc容器

    从标签“源码”来看,这个项目可能提供了源代码,供学习者研究和分析。通过阅读源码,开发者可以深入了解IoC容器的工作原理,包括如何解析配置,如何实例化和管理Bean,以及如何处理依赖关系。这对于理解Spring框架...

    spring源代码

    源代码分析有助于深入理解Spring的工作原理,提升编程技能,并且能够帮助开发者在遇到问题时进行调试和优化。 1. **Spring IoC容器**: Spring的核心是IoC容器,它负责管理对象的生命周期和依赖关系。通过XML配置...

    简单IOC容器demo

    1. 源代码文件(.java):这些文件可能包含了实现IOC容器的类,如一个用于扫描注解并处理依赖注入的主容器类,以及带有注解的被注入对象类。 2. 注解(Annotations):例如`@Autowired`或自定义注解,用于标记需要...

    IOC容器简单实现

    IOC(Inversion of Control)容器是软件设计模式中的一种,它将对象的创建和管理权从代码本身转移到一个外部容器,即IOC容器。这种反转控制使得程序更加灵活,降低了组件之间的耦合性,提高了可测试性和可维护性。本...

    精通spring源代码精通spring源代码

    要真正精通Spring源代码,除了理解上述知识点外,还需要阅读和分析Spring的源码,理解其实现细节和设计模式。Spring源码中包含了大量优秀的编程实践,如工厂模式、代理模式、观察者模式等,这些都是提升编程技能的...

    spring_ioc spring ioc

    ### Spring IoC容器的核心概念与应用 #### 一、IoC基本定义 IoC(Inversion of Control,控制反转)是一种设计思想,在Spring框架中主要体现在这样一种方式:原本在程序代码中由开发者自己控制的对象的创建过程以及...

    精通spring 源代码

    《精通Spring源代码》是罗时飞先生关于Spring框架深入解析的一部著作,旨在帮助开发者更深入地理解Spring的工作原理,提升对Java企业级应用开发的掌控能力。本压缩包包含的文件名为“精通Spring源码”,这通常是一个...

    springIOC核心组件分析.vsdx

    spring-context:上下文,即IOC容器 spring-context-support:对IOC的扩展,以及IOC子容器 spring-context-indexer:类管理组件和Classpath扫描 spring-expression:表达式语句 切面编程: spring-aop:面向切面编程,...

Global site tag (gtag.js) - Google Analytics