【spring源代码分析】--Bean的解析与注冊
2016-01-22 14:09
423 查看
接着上一节继续分析,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容器的初始化完毕,容器已经能够使用了。接下来就是进行依赖注入。敬请期待下一节!
相关文章推荐
- Hive学习1_hive配置遇到的问题:Relative path in absolute URI: ${system:java.io.tmpdir%7D/$%7Bsystem:user.name%
- JAVA设计模式:组合模式
- eclipse快捷键汇总
- java基础篇--01<基础>
- java.lang.IllegalStateException: ScrollView can host only one direct child
- JavaEE 之 JPA 常见异常处理办法汇总
- 关于struts2的那点事
- static关键字--java
- Vector and ArrayList in Java
- Java 方法
- 手动编译JAVA类
- JavaSE001_String类总结之构造器和常用方法
- android studio 导入eclipse遇到的相关问题
- java ftp相关的异常汇总
- Spring+MVC项目发布停止
- java前台传参json,后台用map或者实体对象接收
- java.lang.RuntimeException: JPedal Trial has now expired
- java 实现多线程的三种基本方式
- 深度分析 Java 的枚举类型:枚举的线程安全性及序列化问题
- JAVA注解