初始化IoC容器(Spring源码阅读)
2013-08-12 10:47
721 查看
初始化IoC容器(Spring源码阅读)
我们到底能走多远系列(31)
扯淡:有个问题一直想问:各位你们的工资剩下来会怎么处理?已婚的,我知道工资永远都是不够的。未婚的你们,你们是怎么分配工资的?
毕竟,对自己的收入的分配差不多体现了自己的现状,以及自己对自己未来有什么样的期许~
主题:
本人在阅读源码基本参考了《Spring技术内幕:深入解析 Spring架构与设计原理》,很不错的书籍,建议大家阅读。
初始化IoC容器:1,resource定位 2,BeanDefinition载入 3,把BeanDefinition载入到IoC
重要的解释:
Spring中的[b]IoC容器,所谓的容器核心就是个hashMap,准确的说是ConcurrentHashMap,键值对就是:<String, BeanDefinition> key是bean的name。[/b]
[b] 那么[b][b]BeanDefinition[/b]就是对外界bean描述的抽象,比如你写的<bean>标签,最会被抽象成一个[b][b][b]BeanDefinition[/b]放进这个Map中去。[/b][/b][/b][/b]
[b][b][b] 所以一个完整的[b][b]IoC容器[/b]来说,只要提供对这个Map的必要操作就可以了。一般[/b][/b][/b]DefaultListableBeanFactory 作为一个默认功能完整的IoC容器来使用。[/b]
上面的解释已经很清楚了,[b][b]IoC容器[/b]的初始化就可以理解成,我们有个xml描述了一些bean的属性,Spring把它读进来,按照自己的规则解析一边,把其中的Bean描述转换成一个个[b][b][b]BeanDefinition[/b][/b]放进Map中去就完成初始化了。[/b][/b]
拿FileSystemXmlApplicationContext为例子看一下源码中是如何实现的:(希望有兴趣的先看下Spring中BeanFactory下面的继承结构)
我们会写类似下面的代码开始我们的Spring之旅:
View Code
View Code
上面解析的代码中有调用的一个方法parseBeanDefinitionElement(Element ele, String beanName, BeanDefinition containingBean)带我们去解析bean中更加详细的属性:
public AbstractBeanDefinition parseBeanDefinitionElement( Element ele, String beanName, BeanDefinition containingBean) { this.parseState.push(new BeanEntry(beanName)); String className = null; if (ele.hasAttribute(CLASS_ATTRIBUTE)) {// class属性 className = ele.getAttribute(CLASS_ATTRIBUTE).trim(); } try { String parent = null; if (ele.hasAttribute(PARENT_ATTRIBUTE)) {// parent属性 parent = ele.getAttribute(PARENT_ATTRIBUTE); } AbstractBeanDefinition bd = createBeanDefinition(className, parent); // 下面parse方法解析其他的属性 parseBeanDefinitionAttributes(ele, beanName, containingBean, bd); bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT)); parseMetaElements(ele, bd); parseLookupOverrideSubElements(ele, bd.getMethodOverrides()); parseReplacedMethodSubElements(ele, bd.getMethodOverrides()); parseConstructorArgElements(ele, bd); parsePropertyElements(ele, bd); parseQualifierElements(ele, bd); bd.setResource(this.readerContext.getResource()); bd.setSource(extractSource(ele)); return bd; } // 下面的错误用spring有时候有看见过吧 catch (ClassNotFoundException ex) { error("Bean class [" + className + "] not found", ele, ex); } catch (NoClassDefFoundError err) { error("Class that bean class [" + className + "] depends on not found", ele, err); } catch (Throwable ex) { error("Unexpected failure during bean definition parsing", ele, ex); } finally { this.parseState.pop(); } return null; }
以上就是解析好了,然后就是放进传说中的IoC容器里啦:
BeanDefinitionReaderUtils的registerBeanDefinition方法:
public static void registerBeanDefinition( BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException { // Register bean definition under primary name. String beanName = definitionHolder.getBeanName(); // 调用了下BeanDefinitionRegistry 的方法, // 而这个registry就是DefaultListableBeanFactory,所有的BeanDefinition都要注册到它里面去呀... registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition()); // Register aliases for bean name, if any. String[] aliases = definitionHolder.getAliases(); if (aliases != null) { for (String aliase : aliases) { registry.registerAlias(beanName, aliase); } } }
DefaultListableBeanFactory的registerBeanDefinition:
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException { Assert.hasText(beanName, "Bean name must not be empty"); Assert.notNull(beanDefinition, "BeanDefinition must not be null"); if (beanDefinition instanceof AbstractBeanDefinition) { try { ((AbstractBeanDefinition) beanDefinition).validate(); } catch (BeanDefinitionValidationException ex) { throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Validation of bean definition failed", ex); } } synchronized (this.beanDefinitionMap) { Object oldBeanDefinition = this.beanDefinitionMap.get(beanName); // 保证加载bean唯一性 if (oldBeanDefinition != null) { if (!this.allowBeanDefinitionOverriding) { throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName + "': There is already [" + oldBeanDefinition + "] bound."); } else { if (this.logger.isInfoEnabled()) { this.logger.info("Overriding bean definition for bean '" + beanName + "': replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]"); } } } else { this.beanDefinitionNames.add(beanName); this.frozenBeanDefinitionNames = null; } // 放到前面提到的[b]ConcurrentHashMap[/b]里面去喽~ this.beanDefinitionMap.put(beanName, beanDefinition); resetBeanDefinition(beanName); } }
以上就是初始化IoC容器的过程。各位有兴趣可以自己debug进去一步步看既可以了。
另外用maven的话直接用下面命令下载源码即可:
mvn dependency:sources
让我们继续前行
----------------------------------------------------------------------
努力不一定成功,但不努力肯定不会成功。
共勉。
相关文章推荐
- Spring源码阅读之IoC容器初始化1 -- Resource定位
- Spring源码阅读之IoC容器初始化2 -- BeanDefinition载入与解析
- Spring源码阅读之IoC容器初始化3 -- BeanDefinition在IoC容器中的注册
- Spring源码阅读(二)—IOC容器初始化
- Spring源码阅读(一):IOC容器的初始化
- Spring 源码阅读五 IOC容器初始化之bean定义载入
- 初始化IoC容器(Spring源码阅读)-我们到底能走多远系列(31)
- Spring源码阅读-- IOC容器资源定位
- Spring IOC 容器源码分析 - 余下的初始化工作
- spring源码学习之路---深度分析IOC容器初始化过程(三)
- 【Spring】IOC核心源码学习(二):容器初始化过程
- Spring源码分析(二)-Spring IoC容器的初始化No.2
- Spring IoC源码解析(一)——配置文件加载和IoC容器初始化
- 【spring源码学习】spring的IOC容器在初始化bean过程
- spring源码研究之IoC容器在web容器中初始化过程
- 【Spring】IOC核心源码学习:容器初始化过程
- spring源码学习之路---IOC容器初始化要义之bean定义载入(五)
- spring源码 — 一、IoC容器初始化
- Spring源码阅读-- IOC容器资源解析
- Spring源码阅读--BeanDefinition 在 IOC 容器中的注册