【spring源码分析】--Bean的解析与注册
2015-07-07 22:32
776 查看
接着上一节继续分析,DefaultBeanDefinitionDocumentReader的parseBeanDefinitions方法:
上面的代码就是一个遍历根节点的子节点的代码,也就是循环处理节点,处理的方法是parseDefaultElement,进入parseDefaultElement方法,我们发现根据不同的节点名称,有不同的处理方法,我们关心的bean节点的处理方法,自然进入processBeanDefinition方法。
好了,我们发现,真正的处理逻辑是在BeanDefinitionParserDelegate类的parseBeanDefinitionElement方法里
我们关注一下更加详细的解析,也就是parseBeanDefinitionElement的另一个重载方法
上面就是一个具体生成BeanDefinition对象的方法,经过这么多步骤,终于把xml中定义的一个bean元素转换成spring定义的BeanDefinition对象了,接下来就是注册这个BeanDefinition到IOC容器中。
其实IOC容器是通过一个HashMap来持有这些BeanDefinition的,这个HashMap的定义可以在DefaultListableBeanFactory类中找到:
具体的注册方法是在DefaultListableBeanFactory类的registerBeanDefinition方法里:
这就完成了Bean的注册,IoC容器的初始化完成,容器已经可以使用了,接下来就是进行依赖注入,敬请期待下一节!
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) { if (delegate.isDefaultNamespace(root)) { NodeList nl = root.getChildNodes(); for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); if (node instanceof Element) { Element ele = (Element) node; if (delegate.isDefaultNamespace(ele)) { parseDefaultElement(ele, delegate); } else { delegate.parseCustomElement(ele); } } } } else { delegate.parseCustomElement(root); } }
上面的代码就是一个遍历根节点的子节点的代码,也就是循环处理节点,处理的方法是parseDefaultElement,进入parseDefaultElement方法,我们发现根据不同的节点名称,有不同的处理方法,我们关心的bean节点的处理方法,自然进入processBeanDefinition方法。
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) { //BeanDefinitionHolder封装了BeanDefinition、Bean的名字和别名,用它来完成向IOC容器注册 BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); if (bdHolder != null) { bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); try { // Register the final decorated instance. //这里是向IOC容器注册解析得到的BeanDefinition BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry()); } catch (BeanDefinitionStoreException ex) { getReaderContext().error("Failed to register bean definition with name '" + bdHolder.getBeanName() + "'", ele, ex); } // Send registration event. getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder)); } }
好了,我们发现,真正的处理逻辑是在BeanDefinitionParserDelegate类的parseBeanDefinitionElement方法里
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) { String id = ele.getAttribute(ID_ATTRIBUTE); String nameAttr = ele.getAttribute(NAME_ATTRIBUTE); List<String> aliases = new ArrayList<String>(); if (StringUtils.hasLength(nameAttr)) { String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS); aliases.addAll(Arrays.asList(nameArr)); } String beanName = id; if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) { beanName = aliases.remove(0); if (logger.isDebugEnabled()) { logger.debug("No XML 'id' specified - using '" + beanName + "' as bean name and " + aliases + " as aliases"); } } if (containingBean == null) { checkNameUniqueness(beanName, aliases, ele); } //这个方法会对Bean元素进行详细解析 AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean); if (beanDefinition != null) { if (!StringUtils.hasText(beanName)) { try { if (containingBean != null) { beanName = BeanDefinitionReaderUtils.generateBeanName( beanDefinition, this.readerContext.getRegistry(), true); } else { beanName = this.readerContext.generateBeanName(beanDefinition); // Register an alias for the plain bean class name, if still possible, // if the generator returned the class name plus a suffix. // This is expected for Spring 1.2/2.0 backwards compatibility. String beanClassName = beanDefinition.getBeanClassName(); if (beanClassName != null && beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() && !this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) { aliases.add(beanClassName); } } if (logger.isDebugEnabled()) { logger.debug("Neither XML 'id' nor 'name' specified - " + "using generated bean name [" + beanName + "]"); } } catch (Exception ex) { error(ex.getMessage(), ele); return null; } } String[] aliasesArray = StringUtils.toStringArray(aliases); return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray); } return null; }
我们关注一下更加详细的解析,也就是parseBeanDefinitionElement的另一个重载方法
public AbstractBeanDefinition parseBeanDefinitionElement( Element ele, String beanName, BeanDefinition containingBean) { this.parseState.push(new BeanEntry(beanName)); //这里只是解析出class名字,并没有去进行实例化 String className = null; if (ele.hasAttribute(CLASS_ATTRIBUTE)) { className = ele.getAttribute(CLASS_ATTRIBUTE).trim(); } try { String parent = null; if (ele.hasAttribute(PARENT_ATTRIBUTE)) { parent = ele.getAttribute(PARENT_ATTRIBUTE); } //这里建立了BeanDefinition对象 AbstractBeanDefinition bd = createBeanDefinition(className, parent); //对当前bean元素进行属性解析 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; } 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; }
上面就是一个具体生成BeanDefinition对象的方法,经过这么多步骤,终于把xml中定义的一个bean元素转换成spring定义的BeanDefinition对象了,接下来就是注册这个BeanDefinition到IOC容器中。
其实IOC容器是通过一个HashMap来持有这些BeanDefinition的,这个HashMap的定义可以在DefaultListableBeanFactory类中找到:
/** Map of bean definition objects, keyed by bean name */ private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>(64);
具体的注册方法是在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); } } BeanDefinition oldBeanDefinition; //注册时保证数据一致性 synchronized (this.beanDefinitionMap) { //这里检查是否有同名的bean已经注册了,如果注册了,并且不允许覆盖,则抛出异常 oldBeanDefinition = this.beanDefinitionMap.get(beanName); 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 (oldBeanDefinition.getRole() < beanDefinition.getRole()) { // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE if (this.logger.isWarnEnabled()) { this.logger.warn("Overriding user-defined bean definition for bean '" + beanName + " with a framework-generated bean definition ': replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]"); } } else { if (this.logger.isInfoEnabled()) { this.logger.info("Overriding bean definition for bean '" + beanName + "': replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]"); } } } //下面就是正常注册了,把bean的那么作为key,BeanDefinition对象作为value,放入HashMap中 else { this.beanDefinitionNames.add(beanName); this.frozenBeanDefinitionNames = null; } this.beanDefinitionMap.put(beanName, beanDefinition); } if (oldBeanDefinition != null || containsSingleton(beanName)) { resetBeanDefinition(beanName); } }
这就完成了Bean的注册,IoC容器的初始化完成,容器已经可以使用了,接下来就是进行依赖注入,敬请期待下一节!
相关文章推荐
- jdk安装和环境变量的配置
- Java--内存分配全面浅析
- SpringFramework4系列之SpringJMS:(四)异步接收消息 2.构建监听器
- Java IO流
- javaweb(二):JSP响应数据和浏览器解析数据的编码问题
- java初学4
- springMVC学习笔记-地址显示与访问
- 【Java】检查字符串s2是否为s1旋转而成
- springMVC学习笔记-jsr303使用
- Java 程序流程控制和函数
- Java NIO vs. IO
- 数据挖掘 k-means离群点检测
- Java访问数据库
- 各种排序算法的分析及java实现
- Java中的访问修饰符
- Java 截取字符串
- eclipse构建maven的web项目
- 黑马程序员---Java概述与jdk的安装和配置(一)
- SpringMVC 使用JSR-303进行校验 @Valid
- 【2-3】Java 中的原生数据类型