spring-framework 加载配置文件过程:
根据业务系统运行的环境,选择 ApplicationContext 接口合适的实现类,启动系统先初始化上下文环境,然后通过BeanDefinitionReader 的实现类读取Bean的配置文件。这里配置文件可以是 xml文件,properties文件,yml文件等,也可以是注解形式扫描配置。配置文件读取成功后,将相应的配置转换成 BeanDefinition 的对象实例保存在DefaultListableBeanFactory#beanDefinitionMap 中。紧接着,根据配置的 BeanFactoryPostProcessor 对象列表,进行 BeanDefinition 的扩展处理。( 例如 org.springframework.beans.factory.config.PlaceholderConfigurerSupport: ${} 配置转换成实际的值实现类。org.springframework.beans.factory.config.PropertyOverrideConfigurer: 将 beanName.property 替换成实际的值。 )
--> xml配置
|
ApplicationContext ---> BeanDefinitionReader -+----> yml配置 -----> BeanDefinition ---> DefaultListableBeanFactory ---> BeanFactoryPostProcessor
|
--> Annotation 扫描
这里以 XML 配置的BeanDefinition 进行源码加载分析:
扫VX 领Java资料,前端,测试,python等等资料都有
一. BeanFactory 实例的创建
在 AbstractApplicationContext#obtainFreshBeanFactory 方法中,是进行 bean 处理的入口。
AbstractApplicationContext#obtainFreshBeanFactory
-> AbstractRefreshableApplicationContext#refreshBeanFactory
1.检测是否已经创建 BeanFactory 。如果创建了则销毁BeanFactory 相关的属性。
2.创建 BeanFactory 接口的默认实现类 DefaultListableBeanFactory 实例。
3.客户化 BeanFactory 处理。
4.加载 BeanDefinition 定义信息。
1 /** 2 * This implementation performs an actual refresh of this context's underlying 3 * bean factory, shutting down the previous bean factory (if any) and 4 * initializing a fresh bean factory for the next phase of the context's lifecycle. 5 */ 6 @Override 7 protected final void refreshBeanFactory() throws BeansException { 8 if (hasBeanFactory()) { 9 destroyBeans(); 10 closeBeanFactory(); 11 } 12 try { 13 DefaultListableBeanFactory beanFactory = createBeanFactory(); 14 beanFactory.setSerializationId(getId()); 15 customizeBeanFactory(beanFactory); 16 loadBeanDefinitions(beanFactory); 17 this.beanFactory = beanFactory; 18 } 19 catch (IOException ex) { 20 throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex); 21 } 22 }
二. ApplicationContex 读取 BeanDefinition 的加载分析
这里我们分析 XML 形式配置的加载,因此通过 AbstractXmlApplicationContext 来分析源码。
AbstractApplicationContext#obtainFreshBeanFactory
-> AbstractRefreshableApplicationContext#refreshBeanFactory
--> AbstractXmlApplicationContext#loadBeanDefinitions(DefaultListableBeanFactory)
1.首先创建读取 BeanDefinition 的 BeanDefinitionReader 接口实现 XmlBeanDefinitionReader 实例,并设置环境信息。
2.通过 BeanDefinitionReader 实现读取 BeanDefinition 配置信息。
1 /** 2 * Loads the bean definitions via an XmlBeanDefinitionReader. 3 * @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader 4 * @see #initBeanDefinitionReader 5 * @see #loadBeanDefinitions 6 */ 7 @Override 8 protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException { 9 // Create a new XmlBeanDefinitionReader for the given BeanFactory. 10 XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); 11 12 // Configure the bean definition reader with this context's 13 // resource loading environment. 14 beanDefinitionReader.setEnvironment(this.getEnvironment()); 15 beanDefinitionReader.setResourceLoader(this); 16 beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this)); 17 18 // Allow a subclass to provide custom initialization of the reader, 19 // then proceed with actually loading the bean definitions. 20 initBeanDefinitionReader(beanDefinitionReader); 21 loadBeanDefinitions(beanDefinitionReader); 22 }
三. BeanDefinitionReader 读取,加载 BeanDefinition 配置分析
AbstractXmlApplicationContext#loadBeanDefinitions(DefaultListableBeanFactory)
--> AbstractXmlApplicationContext#loadBeanDefinitions(XmlBeanDefinitionReader)
--> AbstractBeanDefinitionReader#loadBeanDefinitions(String, Set<Resource>)
--> XmlBeanDefinitionReader#loadBeanDefinitions(EncodedResource)
--> XmlBeanDefinitionReader#doLoadBeanDefinitions(InputSource, Resource )
1.读取 XML 文件,获取到 Document 实例。为后续解析配置做准备。
2.向 BeanFactory 中注册 BeanDefinition 配置信息。
此处异常捕获比较多,学习异常规范处理。最底层的 Throwable 异常也捕获了,保证程序不会异常退出。
1 /** 2 * Actually load bean definitions from the specified XML file. 3 * @param inputSource the SAX InputSource to read from 4 * @param resource the resource descriptor for the XML file 5 * @return the number of bean definitions found 6 * @throws BeanDefinitionStoreException in case of loading or parsing errors 7 * @see #doLoadDocument 8 * @see #registerBeanDefinitions 9 */ 10 protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) 11 throws BeanDefinitionStoreException { 12 13 try { 14 Document doc = doLoadDocument(inputSource, resource); 15 int count = registerBeanDefinitions(doc, resource); 16 if (logger.isDebugEnabled()) { 17 logger.debug("Loaded " + count + " bean definitions from " + resource); 18 } 19 return count; 20 } 21 catch (BeanDefinitionStoreException ex) { 22 throw ex; 23 } 24 catch (SAXParseException ex) { 25 throw new XmlBeanDefinitionStoreException(resource.getDescription(), 26 "Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex); 27 } 28 catch (SAXException ex) { 29 throw new XmlBeanDefinitionStoreException(resource.getDescription(), 30 "XML document from " + resource + " is invalid", ex); 31 } 32 catch (ParserConfigurationException ex) { 33 throw new BeanDefinitionStoreException(resource.getDescription(), 34 "Parser configuration exception parsing XML from " + resource, ex); 35 } 36 catch (IOException ex) { 37 throw new BeanDefinitionStoreException(resource.getDescription(), 38 "IOException parsing XML document from " + resource, ex); 39 } 40 catch (Throwable ex) { 41 throw new BeanDefinitionStoreException(resource.getDescription(), 42 "Unexpected exception parsing XML document from " + resource, ex); 43 } 44 }
扫VX 领Java资料,前端,测试,python等等资料都有
四.BeanDefinitionDocumentReader 解析 BeanDefinition 配置分析
(一) BeanDefinitionDocumentReader 分析
XmlBeanDefinitionReader#doLoadBeanDefinitions
--> XmlBeanDefinitionReader#registerBeanDefinitions(Document, Resource)
--> BeanDefinitionDocumentReader#registerBeanDefinitionsregisterBeanDefinitions(Document, XmlReaderContext)
1. 创建 BeanDefinitionDocumentReader 对象实例。
2.创建 读取 BeanDefinition 配置信息Document的上下文(XmlReaderContext),为后续解析配置提供相关支持。
3. 解析并注册Document 中配置的 BeanDefinition 信息。在 DefaultBeanDefinitionDocumentReader 实现具体逻辑。
1 /** 2 * Register the bean definitions contained in the given DOM document. 3 * Called by {@code loadBeanDefinitions}. 4 * <p>Creates a new instance of the parser class and invokes 5 * {@code registerBeanDefinitions} on it. 6 * @param doc the DOM document 7 * @param resource the resource descriptor (for context information) 8 * @return the number of bean definitions found 9 * @throws BeanDefinitionStoreException in case of parsing errors 10 * @see #loadBeanDefinitions 11 * @see #setDocumentReaderClass 12 * @see BeanDefinitionDocumentReader#registerBeanDefinitions 13 */ 14 public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException { 15 BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader(); 16 int countBefore = getRegistry().getBeanDefinitionCount(); 17 documentReader.registerBeanDefinitions(doc, createReaderContext(resource)); 18 return getRegistry().getBeanDefinitionCount() - countBefore; 19 }
(二)BeanDefinitionDocumentReader 实现类 DefaultBeanDefinitionDocumentReader分析
BeanDefinitionDocumentReader#registerBeanDefinitionsregisterBeanDefinitions(Document, XmlReaderContext)
--> DefaultBeanDefinitionDocumentReader#registerBeanDefinitions(Document doc, XmlReaderContext readerContext)
--> DefaultBeanDefinitionDocumentReader#doRegisterBeanDefinitions(Element)
1. 根据 ReaderContext 信息,创建对应的 实例。
2. 检查 profile 配置信息。如果不匹配,则不解析当前root节点下的 BeanDefinition 配置。
3. 当前root节点 前置处理。
4. 解析当前 root 节点的 BeanDefinition 配置信息。
5. 当前root节点 后置处理。
(三) DefaultBeanDefinitionDocumentReader#parseBeanDefinitions 分析
DefaultBeanDefinitionDocumentReader#parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate)
--> DefaultBeanDefinitionDocumentReader#parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate)
--> BeanDefinitionParserDelegate#parseCustomElement(Element)
1. 判断 root 节点 DefaultNamespace 是否是 http://www.springframework.org/schema/beans 。
如果是,则遍历子节点进行解析。
当子节点 是 DefaultNamespace 。则使用 DefaultBeanDefinitionDocumentReader#parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) 解析节点。
否做使用 BeanDefinitionParserDelegate#parseCustomElement(Element) 解析节点。
2. 非默认 DefaultNamespace 值,则使用 BeanDefinitionParserDelegate#parseCustomElement(Element) 解析节点。
例如 AOP 配置节点解析。例如:<aop:config>
事物配置节点解析。例如:<tx:annotation-driven proxy-target-class="true" />
(四) 解析 DefaultNamespace 节点 BeanDefinition 信息。
DefaultBeanDefinitionDocumentReader#parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate)
--> DefaultBeanDefinitionDocumentReader#importBeanDefinitionResource(Element)
--> DefaultBeanDefinitionDocumentReader#processAliasRegistration(Element)
--> DefaultBeanDefinitionDocumentReader#processBeanDefinition(Element, BeanDefinitionParserDelegate)
--> DefaultBeanDefinitionDocumentReader#doRegisterBeanDefinitions(Element)
1.依次解析 import 节点,alias 节点,bean节点, beans节点 定义的 BeanDefinition 信息。
(五) 解析 非默认命名空间节点 BeanDefinition 信息。
BeanDefinitionParserDelegate#parseCustomElement(Element)
--> BeanDefinitionParserDelegate#parseCustomElement(Element, BeanDefinition)
1.获取节点命名空间。
2.根据命名空间获取对应的解析器。
3. 解析节点 BeanDefinition 信息。
1 /** 2 * Parse a custom element (outside of the default namespace). 3 * @param ele the element to parse 4 * @param containingBd the containing bean definition (if any) 5 * @return the resulting bean definition 6 */ 7 @Nullable 8 public BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) { 9 String namespaceUri = getNamespaceURI(ele); 10 if (namespaceUri == null) { 11 return null; 12 } 13 NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri); 14 if (handler == null) { 15 error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele); 16 return null; 17 } 18 return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd)); 19 }
五.BeanDefinitionDocumentReader 解析 bean 节点
XmlBeanDefinitionReader#loadBeanDefinitions(EncodedResource)
--> XmlBeanDefinitionReader#doLoadBeanDefinitions(InputSource, Resource)
--> XmlBeanDefinitionReader#registerBeanDefinitions(Document, Resource)
--> DefaultBeanDefinitionDocumentReader#registerBeanDefinitions(Document, XmlReaderContext)
--> DefaultBeanDefinitionDocumentReader#doRegisterBeanDefinitions(Element)
--> DefaultBeanDefinitionDocumentReader#parseBeanDefinitions(Element , BeanDefinitionParserDelegate)
--> DefaultBeanDefinitionDocumentReader#parseDefaultElement(Element, BeanDefinitionParserDelegate)
--> DefaultBeanDefinitionDocumentReader#processBeanDefinition(Element, BeanDefinitionParserDelegate)
1.使用 BeanDefinitionParserDelegate 解析 Bean 配置节点,得到保存 BeanDefinition 信息的辅助对象 BeanDefinitionHolder 实例。
2.当 解析的 Bean 配置 BeanDefinitionHolder 实例不为空,则进行 Bean 配置 后续处理。
a. 当 Bean 配置节点 找到 其他 Namespace 对应 处理器(NamespaceHandler),则进行特殊化处理。
b. 向 BeanFactory 中注册解析成功的 BeanDefinition 定义。
c.发送 BeanDefinition 解析成功事件 BeanComponentDefinition。
1 /** 2 * Process the given bean element, parsing the bean definition 3 * and registering it with the registry. 4 */ 5 protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) { 6 BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); 7 if (bdHolder != null) { 8 bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); 9 try { 10 // Register the final decorated instance. 11 BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry()); 12 } 13 catch (BeanDefinitionStoreException ex) { 14 getReaderContext().error("Failed to register bean definition with name '" + 15 bdHolder.getBeanName() + "'", ele, ex); 16 } 17 // Send registration event. 18 getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder)); 19 } 20 }
扫VX 领Java资料,前端,测试,python等等资料都有
六. BeanDefinitionParserDelegate#parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition) 解析 bean 节点
DefaultBeanDefinitionDocumentReader#processBeanDefinition(Element, BeanDefinitionParserDelegate)
--> BeanDefinitionParserDelegate#parseBeanDefinitionElement(Element)
--> BeanDefinitionParserDelegate#parseBeanDefinitionElement(Element, BeanDefinition)
1.解析 Element 元素的 id 和 name 属性,得到 beanName 和 aliases。
2.检查 beanName 是否唯一。
3. 创建 AbstractBeanDefinition 对象实例 bd ,并通过依次解析 Element 元素的属性给 bd 赋值。
依次解析子节点 meta, lookup-method, replaced-method, constructor-arg, property, qualifier,并将解析后的值添加到 bd 相关变量。
设置 bd 解析资源的相关信息。
4. 如果 3 解析失败,则返回的 实例BeanDefinition 为 null,则这里也直接返回。
5. 当上述步骤解析的 beanName 为 空时,使用指定方式生成 beanName。
当前 bean 是在其他Bean 内部时, 使用BeanDefinitionReaderUtils#generateBeanName(BeanDefinition, BeanDefinitionRegistry, boolean) 生成 beanName。
否则使用 XmlReaderContext 对应生成器生成 beanName。
6.根据解析的 BeanDefinition 创建对应的 BeanDefinitionHolder 对象实例。
在解析 bean 配置信息时,主要有如下 七个元数据包装类,对相关属性配置进行归档:
org.springframework.beans.factory.config.ConstructorArgumentValues <constructor-arg>
org.springframework.beans.PropertyValue <property>
org.springframework.beans.factory.support.ManagedArray <array>
org.springframework.beans.factory.support.ManagedList <list>
org.springframework.beans.factory.support.ManagedSet <set>
org.springframework.beans.factory.support.ManagedMap <map>
org.springframework.beans.factory.support.ManagedProperties <props>
每个配置具体字符串值对应了如下三种 处理类型:
org.springframework.beans.factory.config.TypedStringValue <value>
org.springframework.beans.factory.config.RuntimeBeanReference <ref>
org.springframework.beans.factory.config.RuntimeBeanNameReference <idref>
View Code
七. BeanDefinitionParserDelegate#decorateIfRequired(Node, BeanDefinitionHolder, @Nullable BeanDefinition)解析 bean 节点自定义属性
DefaultBeanDefinitionDocumentReader#processBeanDefinition(Element, BeanDefinitionParserDelegate)
--> BeanDefinitionParserDelegate#parseBeanDefinitionElement(Element)
--> BeanDefinitionParserDelegate#decorateBeanDefinitionIfRequired(Element, BeanDefinitionHolder)
--> BeanDefinitionParserDelegate#decorateBeanDefinitionIfRequired(Element, BeanDefinitionHolder, BeanDefinition)
--> BeanDefinitionParserDelegate#decorateIfRequired(Node, BeanDefinitionHolder, @Nullable BeanDefinition)
1. 获得节点(Node) 的命名空间URI(NamespaceURI)。
2. 如果命名空间URI不是默认的,则进行特殊处理。
3. 通过 命名空间URI 到读取文件上下文(XmlReaderContext) 中查找对应 处理器(NamespaceHandler)。
例如
Context的处理器: org.springframework.context.config.ContextNamespaceHandler
AOP的处理器: org.springframework.aop.config.AopNamespaceHandler
component的处理器: org.springframework.beans.factory.xml.ComponentNamespaceHandler
4. 调用 NamespaceHandler#decorate(Node, BeanDefinitionHolder, ParserContext)方法解析 节点配置信息,并返回新的 BeanDefinitionHolder 实例。
View Code
八. BeanDefinitionReaderUtils#registerBeanDefinition(BeanDefinitionHolder, BeanDefinitionRegistry) 向 BeanFactory 注册 BeanDefinition 实例信息
1. 通过 beanName 向 beanFactory 中注册 BeanDefinition 实例。
2. 通过 beanName 向 beanFactory 中注册 BeanDefinition 实例的别名列表。
View Code
扫VX 领Java资料,前端,测试,python等等资料都有