spring beans源码解读之--XmlBeanFactory
导读:
XmlBeanFactory继承自DefaultListableBeanFactory,扩展了从xml文档中读取bean definition的能力。从本质上讲,XmlBeanFactory等同于DefaultListableBeanFactory+XmlBeanDefinitionReader ,如果有更好的需求,可以考虑使用DefaultListableBeanFactory+XmlBeanDefinitionReader方案,因为该方案可以从多个xml文件读取资源,并且在解析xml上具有更灵活的可配置性。
1 XmlBeanFactory的使用
典型构造方法:
- public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
- super(parentBeanFactory);
- this.reader.loadBeanDefinitions(resource);
- }
其中,
reader是XmlBeanDefinitionReader的实例,XmlBeanDefinitionReader继承自AbstractBeanDefinitionReader(http://www.cnblogs.com/davidwang456/p/4190428.html 已经介绍过)。
Resource 接口封装了各种可能的资源类型,也就是对使用者来说屏蔽了文件类型的不同。这样所有的资源都被可以通过 InputStream 这个类来获取,所以也屏蔽了资源的提供者。另外还有一个问题就是加载资源的问题,也就是资源的加载者要统一,从上图中可以看出这个任务是由 ResourceLoader 接口完成,他屏蔽了所有的资源加载者的差异,只需要实现这个接口就可以加载所有的资源,他的默认实现是 DefaultResourceLoader。
1.1 Resource 接口继承了 InputStreamSource 接口,这个接口中有个 getInputStream 方法,返回的是 InputStream 类。
- public interface InputStreamSource {
- InputStream getInputStream() throws IOException;
- }
- getInputStream设计希望每次请求都返回一个新的流。这种要求在一个场合非常重要,例如javamail api,它在创建多个邮件附件时需要多次读取到流,在这中情况下,它就要求每个getInputStream请求能返回一个新的流。
- 1.2 抽象资源类AbstractResource继承自Source接口,实现了部分方法。
exists方法检查一个文件或者输入量是否可以打开;
isOpen 通常返回false;
getUrl和getFile 抛出异常;
toString返回描述信息。- 另外有一个有用的方法:lastModified()返回文件的最后修改时间。调用了File.lastModified() 返回此抽象路径名表示的文件最后一次被修改的时间。
- @Override
- public long lastModified() throws IOException {
- long lastModified = getFileForLastModifiedCheck().lastModified();
- if (lastModified == 0L) {
- throw new FileNotFoundException(getDescription() +
- " cannot be resolved in the file system for resolving its last-modified timestamp");
- }
- return lastModified;
- }
1.3 Resource的实现子类:
- AbstractResource的直接子类有:AbstractFileResolvingResource, ByteArrayResource,BeanDefinitionResource, DescriptiveResource, FileSystemResource, InputStreamResource, PathResource, VfsResource。
其中,AbstractFileResolvingResource的直接子类有:ClassPathResource, PortletContextResource, ServletContextResource, UrlResource
- 比较重要的实现类为实现了ContextResource接口的资源类,ContextResource接口继承了Resource接口,通过从一个封装的context中加载资源来扩展Resource接口的功能。例如:可以从ServletContext,PortletContext,普通的classpth路径或者文件系统的相对路径(特别是没有指明前缀,因此适用于本地ResourceLoader的context),其子类实现有:PortletContextResource, ServletContextResource,ClassPathContextResource,ClassRelativeContextResource,FileSystemContextResource.
1.4 资源的加载ResourceLoader,ResourceLoader是一个加载资源的策略接口,可以从classpth或者文件系统中,ApplicationContext需要加载资源功能,使用了其扩展类ResourcePatternReolver。DefaultResourceLoader是该接口的标准实现,适用于一个ApplicationContext外部,可以用在ResourceEditor中。在application允许过程中,使用特定的context子原因加载策略,可以将type资源和资源组通过string的形式设置bean的属性。
(来源:http://www.ibm.com/developerworks/cn/java/j-lo-spring-principle/)
2. Bean的解析与注册详细过程分析
(来源:http://www.ibm.com/developerworks/cn/java/j-lo-spring-principle/)
首先, XmlBeanFactory构造函数this.reader.loadBeanDefinitions(resource);
1. XmlBeanDefinitionReader加载bean定义:loadBeanDefinitions方法
2. XmlBeanDefinitionReader解析bean定义,并注册:doLoadBeanDefinitions方法
Document doc = doLoadDocument(inputSource, resource);
return registerBeanDefinitions(doc, resource);
3.1. 使用标准的JAXP配置的xml解析器从Resource中加载到Document。
- /**
- * Load the {@link Document} at the supplied {@link InputSource} using the standard JAXP-configured
- * XML parser.
- */
- @Override
- 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);
- return builder.parse(inputSource);
- }
3.2.根据加载的Document 注册Bean definition。
- public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
- BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
- documentReader.setEnvironment(getEnvironment());
- int countBefore = getRegistry().getBeanDefinitionCount();
- documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
- return getRegistry().getBeanDefinitionCount() - countBefore;
- }
3.2.1 创建BeanDefinitionDocument的解析器BeanUtils.instantiateClass(this.documentReaderClass)
3.2.2 BeanDefinitionDocument解析器注册bean definition,从根节点<beans>开始
- /**
- * Register each bean definition within the given root {@code <beans/>} element.
- */
- protected void doRegisterBeanDefinitions(Element root) {
- String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
- if (StringUtils.hasText(profileSpec)) {
- String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
- profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
- if (!getEnvironment().acceptsProfiles(specifiedProfiles)) {
- return;
- }
- }
- // 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;
- this.delegate = createDelegate(this.readerContext, root, parent);
- preProcessXml(root);
- parseBeanDefinitions(root, this.delegate);
- postProcessXml(root);
- this.delegate = parent;
- }
- /**
- * Parse the elements at the root level in the document:
- * "import", "alias", "bean".
- * @param root the DOM root element of the document
- */
- 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);
- }
- }
- private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
- if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
- importBeanDefinitionResource(ele);
- }
- else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
- processAliasRegistration(ele);
- }
- else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
- processBeanDefinition(ele, delegate);
- }
- else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
- // recurse
- doRegisterBeanDefinitions(ele);
- }
- }
4. documentReader.registerBeanDefinitions(doc, createReaderContext(resource));--->
- public XmlReaderContext createReaderContext(Resource resource) {
- return new XmlReaderContext(resource, this.problemReporter, this.eventListener,
- this.sourceExtractor, this, getNamespaceHandlerResolver());
- }
5.调用:
- protected NamespaceHandlerResolver createDefaultNamespaceHandlerResolver() {
- return new DefaultNamespaceHandlerResolver(getResourceLoader().getClassLoader());
- }
6.BeanDefinitionReaderUtils.registerBeanDefinition
- /**
- * Process the given bean element, parsing the bean definition
- * and registering it with the registry.
- */
- protected 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));
- }
- }
7.处理给定的Bean元素,并解析到BeanDefinition。
- /**
- * Process the given bean element, parsing the bean definition
- * and registering it with the registry.
- */
- protected 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));
- }
- }
8.
- public static void registerBeanDefinition(
- BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
- throws BeanDefinitionStoreException {
- // Register bean definition under primary name.
- String beanName = definitionHolder.getBeanName();
- 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);
- }
- }
- }
9.将解析的Bean定义放入BeanDefinitionNames和BeanDefinitionMap保存已经aliasMap等
- @Override
- 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) {
- 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 + "]");
- }
- }
- }
- else {
- this.beanDefinitionNames.add(beanName);
- this.frozenBeanDefinitionNames = null;
- }
- this.beanDefinitionMap.put(beanName, beanDefinition);
- }
- if (oldBeanDefinition != null || containsSingleton(beanName)) {
- resetBeanDefinition(beanName);
- }
- }
3. 一个非常重要的部分就是建立 Bean 对象实例之间的关系,这也是 Spring 框架的核心竞争力,何时、如何建立他们之间的关系请看下面的时序图:
来源:http://www.ibm.com/developerworks/cn/java/j-lo-spring-principle/
4. 小结:
从spring 3.1版本后,xmlBeanFactory被表明为Deprecated. 推荐使用DefaultListableBeanFactory和XmlBeanDefinitionReader替换。
本文从xmlBeanFactory扩展到XmlBeanDefinitionReader,再到Resource接口。
一些情节还没有理顺,显得有些杂乱,后续会修改(写的很累,休整一下)。写这篇博客的时候,这句话一直在我脑边回想:
"写书就像冒险。一开始它是玩具和娱乐。然后她成了你的情妇。然后是你的主人。然后变成一个暴君。最后你终于认命的时候,它死了,然后给拖到外面游街。" ----温斯顿.丘吉尔
参考文献:
1. http://www.ibm.com/developerworks/cn/java/j-lo-spring-principle/
spring beans源码解读之--XmlBeanFactory的更多相关文章
- spring beans源码解读
spring beans下面有如下源文件包: org.springframework.beans, 包含了操作java bean的接口和类.org.springframework.beans.anno ...
- spring beans源码解读之--总结篇
spring beans下面有如下源文件包: org.springframework.beans, 包含了操作java bean的接口和类.org.springframework.beans.anno ...
- spring beans源码解读之 ioc容器之始祖--DefaultListableBeanFactory
spring Ioc容器的实现,从根源上是beanfactory,但真正可以作为一个可以独立使用的ioc容器还是DefaultListableBeanFactory,因此可以这么说, DefaultL ...
- spring beans 源码解读
从把spring下下来,导入到eclipse,花了几个小时的时间. 本来壮志雄心的说要,满满深入学习研读spring源码,现在看来还是不太现实,太难懂了,各种依赖,说明都是英文,整个串起来理解,深入研 ...
- spring beans源码解读之--Bean的注解(annotation)
随着spring注解的引入,越来越多的开发者开始使用注解,这篇文章将对注解的机制进行串联式的讲解,不求深入透彻,但求串起spring beans注解的珍珠,展示给大家. 1. spring beans ...
- spring beans源码解读之--bean definiton解析器
spring提供了有两种方式的bean definition解析器:PropertiesBeanDefinitionReader和XmLBeanDefinitionReader即属性文件格式的bean ...
- spring beans源码解读之--BeanFactory进化史
BeanFactory是访问bean容器的根接口,它是一个bean容器的基本客户端视图. 先让我们看看beanfactory的前生后世吧! beanFactory有四个重要的子接口: SimpleJn ...
- spring beans源码解读之--Bean的定义及包装
bean的定义,包装是java bean的基础.再怎么强调它的重要性都不为过,因此深入 了解这块的代码对以后的代码研究可以起到事半功倍的功效. 1. Bean的定义BeanDefinition 1.1 ...
- spring beans源码解读之--BeanFactory的注册
beanFactory的继承关系如下图所示: (图片来源:http://www.myexception.cn/software-architecture-design/925888.html) 在上节 ...
随机推荐
- libSVM 参数选择
libSVM 参数选择 [预测标签,准确率,决策值]=svmpredict(测试标签,测试数据,训练的模型); 原文参考:http://blog.csdn.net/carson2005/art ...
- jquery mobile backbone
http://www.appliness.com/getting-started-with-html-mobile-application-development-using-jquery-mobil ...
- 【POJ 2987】Firing (最小割-最大权闭合子图)
裁员 [问题描述] 在一个公司里,老板发现,手下的员工很多都不务正业,真正干事员工的没几个,于是老板决定大裁员,每开除一个人,同时要将其下属一并开除,如果该下属还有下属,照斩不误.给出每个人的贡献值和 ...
- mysql 连接url中useUnicode=true&characterEncoding=UTF-8 的作用
添加的作用是:指定字符的编码.解码格式. 例如:mysql数据库用的是gbk编码,而项目数据库用的是utf-8编码.这时候如果添加了useUnicode=true&cha ...
- NAND FLASH的容量、特性、市场和应用
NAND Flash的容量 一直到2006年,MLC芯片的容量每年都成倍数增长:由于NAND Flash的制程升级的挑战越来越大,所以NAND Flash之后的容量成倍增长所需要的时间也在不断增加 ...
- Sharepoint 2010 之 WebPart
转:http://blog.csdn.net/bestbadgod/article/details/6895542 Sharepoint系列的博客,都是我个人自学过程中的点滴的积累,毕竟没做过C#及A ...
- 国内外最全的asp.net开源项目
转自:http://www.cnblogs.com/fengtangquan/archive/2010/10/19/1855472.html 最近一些项目开始用到CMS系统,最开始是研究JAVA的,无 ...
- selenium webdriver(2)---页面对象定位
webdriver的元素定位很灵活,提供了多种定位方式: Id LinkText PartialLinkText Name TagName Xpath ClassName CssSelector 这些 ...
- JavaScript---网络编程(2)-函数与数组
上节,学完循环了~ 现在学Javascript的函数和数组. JavaScript语法 每一种语言都有自己的语法规则,JS语法与Java很像,所以学习起来比较容易.JS中也一样有变量,语句,函数,数组 ...
- JavaScript高级程序设计31.pdf
其它方面的变化 DOM的其他部分在“DOM2级核心”中也发生了一些变化,这些变化与XML命名空间无关,而是确保API的可靠性及完整性 DocumentType类型的变化 DocumentType类型新 ...