您的位置:首页 > 编程语言 > Java开发

初始化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


让我们继续前行

----------------------------------------------------------------------

努力不一定成功,但不努力肯定不会成功。
共勉。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: