【Spring Framework 深入】—— IoC容器初始化 -> Bean定义资源的载入解析
来源:互联网 发布:软件过期怎么修改 编辑:程序博客网 时间:2024/05/19 22:25
Bean定义资源的载入解析,Resource是Xml文件的资源描述符(resource descriptor)
回到XmlBeanDefinitionReader的loadBeanDefinitions(Resource …)方法
XmlBeanDefinitionReader.java@Override public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException { //将读入的XML资源进行特殊编码处理 return loadBeanDefinitions(new EncodedResource(resource)); } /** * Load bean definitions from the specified XML file. * @param encodedResource the resource descriptor for the XML file, * allowing to specify an encoding to use for parsing the file * @return the number of bean definitions found * @throws BeanDefinitionStoreException in case of loading or parsing errors */ public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException { ...... try { //得到资源Resource的IO流 InputStream inputStream = encodedResource.getResource().getInputStream(); try { //将InputStream包装成InputSource解析流 InputSource inputSource = new InputSource(inputStream); if (encodedResource.getEncoding() != null) { inputSource.setEncoding(encodedResource.getEncoding()); } //这里是实际处理Resource的过程 return doLoadBeanDefinitions(inputSource, encodedResource.getResource()); } finally { inputStream.close(); } } ...... }protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException { try { //将XML文件转换为DOM对象,解析过程由documentLoader实现 Document doc = doLoadDocument(inputSource, resource); //启动对Document对象的解析过程 return registerBeanDefinitions(doc, resource); } ...... }protected Document doLoadDocument(InputSource inputSource, Resource resource) throws Exception { //documentLoader将Resource解析成DOM对象并返回 return this.documentLoader.loadDocument(inputSource, getEntityResolver(), this.errorHandler, getValidationModeForResource(resource), isNamespaceAware()); }
DocumentLoader将Bean定义资源Resource转换成Document对象
DefaultDocumentLoader.java//使用标准的JAXP解析器将载入的Bean定义资源解析成DOM Document实例public Document loadDocument(InputSource inputSource, EntityResolver entityResolver, ErrorHandler errorHandler, int validationMode, boolean namespaceAware) throws Exception { //创建文件解析器工厂 DocumentBuilderFactory factory = createDocumentBuilderFactory(validationMode, namespaceAware); if (logger.isDebugEnabled()) { logger.debug("Using JAXP provider [" + factory.getClass().getName() + "]"); } //创建文档解析器 DocumentBuilder builder = createDocumentBuilder(factory, entityResolver, errorHandler); //解析Bean定义资源 return builder.parse(inputSource); }
该解析过程调用JavaEE标准的JAXP标准进行处理。
至此Spring IoC容器根据定位的Bean定义资源文件,将其加载读入并转换成为Document对象过程完成。
转换成Document对象后,XmlBeanDefinitionReader委派DefaultBeanDefinitionDocumentReader进行实际的解析工作
XmlBeanDefinitionReader.java//Register the bean definitions contained in the given DOM document. public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException { BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader(); int countBefore = getRegistry().getBeanDefinitionCount(); //BeanDefinitionDocumentReader只是一个接口, //实际委派给DefaultBeanDefinitionDocumentReader进行解析 documentReader.registerBeanDefinitions(doc, createReaderContext(resource)); return getRegistry().getBeanDefinitionCount() - countBefore; } protected BeanDefinitionDocumentReader createBeanDefinitionDocumentReader() { return BeanDefinitionDocumentReader.class.cast(BeanUtils.instantiateClass(this.documentReaderClass)); } private Class<?> documentReaderClass = DefaultBeanDefinitionDocumentReader.class;
BeanDefinitionDocumentReader接口通过registerBeanDefinitions方法调用其实现类DefaultBeanDefinitionDocumentReader对Document对象进行解析
DefaultBeanDefinitionDocumentReader.javapublic void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) { this.readerContext = readerContext; logger.debug("Loading bean definitions"); Element root = doc.getDocumentElement(); doRegisterBeanDefinitions(root); }protected void doRegisterBeanDefinitions(Element root) { // Any nested <beans> elements will cause recursion in this method. In // order to propagate and preserve <beans> default-* attributes correctly, // keep track of the current (parent) delegate, which may be null. Create // the new (child) delegate with a reference to the parent for fallback purposes, // then ultimately reset this.delegate back to its original (parent) reference. // this behavior emulates a stack of delegates without actually necessitating one. BeanDefinitionParserDelegate parent = this.delegate; //具体的解析过程由BeanDefinitionParserDelegate实现 //BeanDefinitionParserDelegate中定义了Spring Bean定义XML文件的各种元素 this.delegate = createDelegate(getReaderContext(), root, parent); if (this.delegate.isDefaultNamespace(root)) { String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE); if (StringUtils.hasText(profileSpec)) { String[] specifiedProfiles = StringUtils.tokenizeToStringArray( profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS); if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) { return; } } } //在解析Bean定义之前,进行自定义的解析,增强解析过程的可扩展性 preProcessXml(root); //从Document的根元素开始解析Bean定义的Document对象 parseBeanDefinitions(root, this.delegate); //在解析Bean定义之后,进行自定义的解析,增强解析过程的可扩展性 postProcessXml(root); this.delegate = parent; }protected BeanDefinitionParserDelegate createDelegate( XmlReaderContext readerContext, Element root, BeanDefinitionParserDelegate parentDelegate) { BeanDefinitionParserDelegate delegate = new BeanDefinitionParserDelegate(readerContext); delegate.initDefaults(root, parentDelegate); return delegate; }
上述的流程图如下:
解析过程的核心函数是parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate)
DefaultBeanDefinitionDocumentReader.java//Parse the elements at the root level in the documentprotected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) { //根节点是否使用了Spring默认的XML命名空间 //BeanDefinitionParserDelegate定义了常量,String BEANS_NAMESPACE_URI = "http://www.springframework.org/schema/beans"; if (delegate.isDefaultNamespace(root)) { NodeList nl = root.getChildNodes(); for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); //元素节点是否使用了默认XML命名空间 if (node instanceof Element) { Element ele = (Element) node; if (delegate.isDefaultNamespace(ele)) { //使用Spring的Bean规则解析元素节点 parseDefaultElement(ele, delegate); } else { //没有使用Spring默认的XML命名空间,则使用用户自定义的解析规则解析元素节点 delegate.parseCustomElement(ele); } } } } else { //Document的根节点没有使用Spring默认的命名空间,则使用用户自定义的解析规则解析Document根节点 delegate.parseCustomElement(root); } }//使用Spring的Bean规则解析Document元素节点private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) { //元素节点是<Import> if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) { importBeanDefinitionResource(ele); } //元素节点是<Alias> else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) { processAliasRegistration(ele); } //元素节点是<Bean> else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) { processBeanDefinition(ele, delegate); } //元素节点是<Beans> else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) { // recurse 递归 doRegisterBeanDefinitions(ele); } }
<Import>
和<Alias>
元素解析在DefaultBeanDefinitionDocumentReader中已经完成,对Bean定义资源文件中使用最多的<Bean>
元素交由BeanDefinitionParserDelegate来解析,源码如下
DefaultBeanDefinitionDocumentReader.javaprotected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) { BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); if (bdHolder != null) { bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); try { // Register the final decorated instance. 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.java//解析<Bean>元素的入口public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) { return parseBeanDefinitionElement(ele, null); }//解析Bean定义资源文件中的<Bean>元素,这个方法中主要处理<Bean>元素的id,name和别名属性 public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) //详细对<Bean>元素中配置的Bean定义其他属性进行解析,除id,name和别名属性三个以外的其他属性数据 public AbstractBeanDefinition parseBeanDefinitionElement( Element ele, String beanName, BeanDefinition containingBean)
注意,在上述解析过程中,只是根据元素的配置信息创建了相应的定义类BeanDefinition,没有创建和实例化Bean对象,依赖注入才会使用这些记录信息创建和实例化具体的Bean对象
<Bean>
常用的属性配置:id、name、alias和property
篇幅较大。。。留到以后再详细学习。
向IoC容器注册BeanDefinition
通过Spring IoC容器对Bean定义资源的解析后,IoC容器大致完成了管理Bean对象的准备工作,即初始化过程,但是最为重要的依赖注入还没有发生,现在在IoC容器中BeanDefinition存储的只是一些静态信息,接下来需要向容器注册Bean定义信息才能全部完成IoC容器的初始化过程。
回到DefaultBeanDefinitionDocumentReader的processBeanDefinition函数,BeanDefinitionParserDelegate 的BeanDefinitionParserDelegate 函数完成后,返回封装BeanDefinition的BeanDefinitionHold对象,接下来,调用BeanDefinitionReaderUtils的registerBeanDefinition方法向IoC容器注册解析的Bean。
函数调用流程图:
DefaultBeanDefinitionDocumentReader.javaprotected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) { BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); if (bdHolder != null) { bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); try { // Register the final decorated instance. //向容器注册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)); } }
待续。。。
- 【Spring Framework 深入】—— IoC容器初始化 -> Bean定义资源的载入解析
- 【Spring Framework 深入】—— IoC容器初始化 -> Bean定义资源的Resource定位
- 《Spring技术内幕》学习笔记3——IoC容器载入Bean定义资源文件
- 《Spring技术内幕》学习笔记3——IoC容器载入Bean定义资源文件 .
- 《Spring技术内幕》学习笔记3——IoC容器载入Bean定义资源文件
- 《Spring技术内幕》学习笔记3——IoC容器载入Bean定义资源文件
- spring技术内幕3-IOC容器载入Bean定义资源
- 《Spring技术内幕》学习笔记4——IoC容器解析Bean定义资源并注册解析后的Bean
- 《Spring技术内幕》学习笔记4——IoC容器解析Bean定义资源并注册解析后的Bean
- 《Spring技术内幕》学习笔记4——IoC容器解析Bean定义资源并注册解析后的Bean
- spring技术内幕4-IoC容器解析Bean定义资源并注册解析后的Bean
- Spring源码学习IOC(3):IoC容器载入Bean定义资源文件
- 深入解读Spring Framework IoC容器(第八弹:Bean的初始化和销毁)
- Spring源码学习IOC(4):IoC容器解析Bean定义资源并注册解析后的Bean
- spring源码学习之路---IOC容器初始化要义之bean定义载入(五)
- spring源码学习之路---IOC容器初始化要义之bean定义载入
- Spring 源码阅读五 IOC容器初始化之bean定义载入
- spring源码学习之路---IOC容器初始化要义之bean定义载入(五)
- 面试笔试算法目录
- 模拟实现顺序表
- ReactNative(二)——HelloWorld
- c++第六次实验
- LeetCode 91. Decode Ways(解码方法)
- 【Spring Framework 深入】—— IoC容器初始化 -> Bean定义资源的载入解析
- 【网络】HTTP基础总结
- 自定义View之onMeasure()
- C++作业6
- U-Boot移植——Nand Flash启动
- 【网络】TCP基础总结
- HDU - 1233 还是畅通工程(Kruskal - MST)
- Java动态代理与Cglib库
- 纪念杨绛先生