1、Spring32 中 Bean 定义之基于 XML 配置方式的源码解析Spring3.2 中 Bean 定义之基于 XML 配置方式的源码解析看看新闻网看引擎IBMSpring 作为成熟的开源框架,已被开发人员广泛使用于日常开发中。Spring 自带的参考文档给开发人员提供了详细的使用介绍。而作为开源框架的 Spring 源码,更为开发人员提供了许多优雅的设计思想和具体实现参考。文章开始前,我们定义一个名词:Bean Definition:即 Bean 定义,对应于 Spring 框架对一个 Bean 的定义,包括各种不同的属性参数,每个 Bean 都有一个或多个相关的 Bean Defini
2、tion。 为了文章的可读性,在此我使用斜体表示,不将其翻译。与 Java 程序中一个对象的执行大概经历定义、实例化和使用等阶段相似。Spring 容器中对象更加明确的经历了定义、实例化和使用等阶段: 对象定义: Spring 容器启动时,会根据开发人员对 Bean(对象)的定义,统一解析这些 Beans 到Bean Definition容器 (ConcurrentHashMapbeanDefinitionMap) 中。同时 Spring 也会解析一些容器启动所必须的和一些默认行为的 Beans 到Bean Definition容器中。 对象实例化: Spring 容器根据一定的规则,将 be
3、anDefinitionMap 中的每个Bean Definition实例化为具体的 Java 对象,同时会将 Singleton 类型的对象缓存到 bean 容器 (ConcurrentHashMap singletonObjects) 中。 对象使用: 前两步骤为 Spring 容器启动时执行,该步骤为应用程序在执行相关业务逻辑时,会到 Spring 容器中找出(Single 类型)或者实例化(如 Prototype 类型)相关对象,供业务逻辑使用。本文主要分析 Spring IoC 容器解析基于 XML 配置方式的Bean Definition的源码实现,给开发人员提供一个知其然,并知其
4、所以然的途径。Spring 简介及 Bean Definition 配置方式Spring 是 2003 年兴起的一个轻量级 Java 开发框架,经过十多年的不断积累和演进,如今已成为功能相同或相似解决方案最为流行的开源框架。Spring IoC 改变了传统的对象定义和使用方式,Spring AOP 为开发人员提供了一种简单但功能强大的面向切面的编程方式,Spring MVC 简化了 WEB 开发的流程,使得开发人员更能专注于业务逻辑代码的开发。Spring 可以用在各种类型的应用开发上。对于 Web Project, 开发人员只要在 web.xml 加入下列代码,并将相关 Spring 依赖文
5、件引入就可以在开发中使用 Spring。清单 1. Web.xml 引入 Spring org.springframework.web.context.ContextLoaderListener 这是一个典型的 ServletContextListener,Servlet 容器(如 Tomcat 等)在启动时会找到 ContextLoaderListener 并执行其 contextInitialized(ServletContextEvent event) 方法。从这里开始,Spring 将会进行Bean Definition的解析、Bean Processors 设置和处理、Beans 实
6、例化等工作。从而将程序会用到的 Java 对象定义并根据该定义创建好,提供给开发人员去使用。这里 Spring 首先需要处理的就是 Bean 的定义。经过不断的发展和演化,Bean 的定义方式有: 基于 XML 文件的配置方式。 基于 Annotation 的配置方式。 基于 Java Code 的配置方式。 用户自定义的配置方式。回页首基于 XML 配置 Bean Definition 的源码解读XML 配置 root WebApplicationContext前文介绍,Servlet 容器启动时如果 web.xml 配置了 ContextLoaderListener,则会调用该对象的初始化
7、方法。根据 Java 语法规定,ContextLoaderListener 的父类 ContextLoader 有一段 static 的代码会更早被执行,这段代码配置了 XML 默认使用的 Context 为org.springframework.web.context.WebApplicationContext = org.springframework.web.context.support.XmlWebApplicationContext根据该定义,如果开发人员没有从 web.xml 指定 contextClass 参数,则默认使用 XmlWebApplicationContext 作为
8、 root WebApplicationContext 工具类。XML 命名空间及 XML 配置文件解析Spring 采用 XML 命名空间的方式,为框架的扩展提供了极大的方便。清单 2. XML 配置文件的命名空间定义 清单 2 展示在 XML 配置文件中引入命名空间的配置范例。图 1. XML 命名空间及其 handler 定义(查看大图)展开 Spring 的依赖 jar 文件,可以看到 Spring 各个模块对应的 jar 包都包含一个 META-INF 目录,如果使用了命名空间,则该目录包含了 spring.schemas 和 spring.handlers 两个文件,如图 1 所示
9、。然后 Spring 代码通过 Properties 工具类扫描 project 的 classpath 以及其使用的所有依赖包中 META-INF 目录来得到对应参数值供后续使用。PropertiesLoaderUtils.loadAllProperties(“META-INF/spring.schemas”,this.classLoader);PropertiesLoaderUtils.loadAllProperties(“META-INF/spring.handlers”,this.classLoader);清单 3. JAXP 方式解析 XML 文件为 Java 对象 protecte
10、d int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException try int validationMode = getValidationModeForResource(resource); / 使用 JAXP 方式,将 XML 配置文件解析为 Java 对象。 Document doc = this.documentLoader.loadDocument(inputSource, getEntityResolver(),this.error
11、Handler, validationMode, isNamespaceAware(); return registerBeanDefinitions(doc, resource); 清单 3 表示 Spring 源码会创建一些必须的属性或对象,读入配置文件(通常为 XML 文件),使用 JAXP 方式将 XML 元素转换为 Java 对象(Document doc)。 这样 Spring 对 XML 配置文件的处理,都可以看作对 Java 对象的处理。图 2. XML 配置文件解析预处理顺序图(查看大图)图 2 展示 Spring 框架如何根据 XML 配置文件,创建辅助类,从而实现对用户自
12、定义的 Bean 解析的过程。详细分析如下:1. Spring 容器在 Servlet 容器启动后,经过一系列的配置和处理到达如下步骤;2. 调用 AbstractApplicationContext 对象的 refreshBeanFactory(); 方法。在这个方法里,将会完成后面所有解析处理。3. 步骤 2 首先创建一个 DefaultListableBeanFactory 对象,该对象的类图如图 3所示。这是 Spring 框架的核心类,Spring 的 Bean 解析和实例化以及后续的使用都跟该类有非常密切的关系。从类图右上角部分可知,该类实现了 BeanFactory 及其几个子接
13、口,这里定义了 DefaultListableBeanFactory 具有的业务接口(如 getBean() 等)。而图的左边的类图展示了 DefaultListableBeanFactory 类的具体业务实现。图 3. DefaultListableBeanFactory 类图(查看大图)4. 调用 XmlWebApplicationContext 对象的 loadBeanDefinitions 方法,其参数为步骤 3 创建的 beanFactory. 这个方法定义了 XmlBeanDefinitionReader 对象 beanDefinitionReader 并设置了其属性 ( 如 Do
14、cumentLoader,EntityResolver 等 ) 用于 XML 文件的解析。XmlWebApplicationContext 对象还负责设置 XML 配置文件名,默认为 /WEB-INF/applicationContext.xml。如果是开发人员定义的配置文件,则可能为多个。5. 该步骤根据步骤 4 定义的配置文件名(一个或多个),调用 beanDefinitionReader 的 loadBeanDefinitions 方法循环解析每个配置文件,传入的参数为配置文件名。6. 步骤 5 的 beanDefinitionReader 会通过 JAXP 方式解析 XML 配置文件为
15、 Document 对象 doc,Spring 框架对 XML 配置文件的处理即转化为对 Java 对象(Document) 的处理。7. 步骤 4 中 beanDefinitionReader 会创建两个对象:DefaultBeanDefinitionDocumentReader 对象 documentReader 和 XmlReaderContext 对象 readerContext. DefaultBeanDefinitionDocumentReader 的属性如清单 4:清单 4. DocumentReader 属性清单public class DefaultBeanDefinitio
16、nDocumentReader implements BeanDefinitionDocumentReader public static final String BEAN_ELEMENT=BeanDefinitionParserDelegate.BEAN_ELEMENT; public static final String NESTED_BEANS_ELEMENT = beans; public static final String ALIAS_ELEMENT = alias; public static final String NAME_ATTRIBUTE = name; publ
17、ic static final String ALIAS_ATTRIBUTE = alias; public static final String IMPORT_ELEMENT = import; public static final String RESOURCE_ATTRIBUTE = resource; /* see org.springframework.context.annotation.Profile */ public static final String PROFILE_ATTRIBUTE = profile; protected final Log logger =
18、LogFactory.getLog(getClass(); private XmlReaderContext readerContext; private Environment environment; private BeanDefinitionParserDelegate delegate; 从上述清单以及 XML 配置对比可知,该对象定义了 元素可配置文件。其第一个属性即为每个 Bean 的配置元素 。readerContext 对象定义了一些如 resource,eventListener 和namespaceHandlerResolver 等上下文信息。通过这些属性,Spring
19、框架获得需要解析的 XML 文件,命名空间解析辅助类以及特定事件的监听器等。8. 以步骤 6 和 7 创建的 doc 和 readerContext 为参数,调用 documentReader 对象的 registerBeanDefinitions 方法。9. 步骤 8 会创建一个工具类 BeanDefinitionParserDelegate ,其部分属性如清单 5。清单 5. BeanDefinitionParserDelegate 属性清单 public class BeanDefinitionParserDelegate . public static final String TRU
20、E_VALUE = true; public static final String FALSE_VALUE = false; public static final String DEFAULT_VALUE = default; public static final String DESCRIPTION_ELEMENT = description; public static final String AUTOWIRE_NO_VALUE = no; public static final String AUTOWIRE_BY_NAME_VALUE = byName; public stat
21、ic final String AUTOWIRE_BY_TYPE_VALUE = byType; public static final String AUTOWIRE_CONSTRUCTOR_VALUE = constructor; public static final String AUTOWIRE_AUTODETECT_VALUE = autodetect; public static final String DEPENDENCY_CHECK_ALL_ATTRIBUTE_VALUE = all; public static final String DEPENDENCY_CHECK_
22、SIMPLE_ATTRIBUTE_VALUE = simple; public static final String DEPENDENCY_CHECK_OBJECTS_ATTRIBUTE_VALUE = objects; public static final String NAME_ATTRIBUTE = name; public static final String BEAN_ELEMENT = bean; public static final String META_ELEMENT = meta; public static final String ID_ATTRIBUTE =
23、id; public static final String PARENT_ATTRIBUTE = parent; public static final String CLASS_ATTRIBUTE = class; public static final String ABSTRACT_ATTRIBUTE = abstract; public static final String SCOPE_ATTRIBUTE = scope; public static final String SINGLETON_ATTRIBUTE = singleton; public static final
24、String LAZY_INIT_ATTRIBUTE = lazy-init; public static final String AUTOWIRE_ATTRIBUTE = autowire; public static final String AUTOWIRE_CANDIDATE_ATTRIBUTE = autowire-candidate; public static final String PRIMARY_ATTRIBUTE = primary; public static final String DEPENDENCY_CHECK_ATTRIBUTE = dependency-c
25、heck; public static final String DEPENDS_ON_ATTRIBUTE = depends-on; public static final String INIT_METHOD_ATTRIBUTE = init-method; public static final String DESTROY_METHOD_ATTRIBUTE = destroy-method; public static final String FACTORY_METHOD_ATTRIBUTE = factory-method; public static final String F
26、ACTORY_BEAN_ATTRIBUTE = factory-bean; public static final String CONSTRUCTOR_ARG_ELEMENT = constructor-arg; public static final String INDEX_ATTRIBUTE = index; public static final String TYPE_ATTRIBUTE = type; public static final String VALUE_TYPE_ATTRIBUTE = value-type; public static final String K
27、EY_TYPE_ATTRIBUTE = key-type; public static final String PROPERTY_ELEMENT = property; public static final String REF_ATTRIBUTE = ref; public static final String VALUE_ATTRIBUTE = value; public static final String LOOKUP_METHOD_ELEMENT = lookup-method; public static final String REPLACED_METHOD_ELEME
28、NT = replaced-method; public static final String REPLACER_ATTRIBUTE = replacer; public static final String ARG_TYPE_ELEMENT = arg-type; public static final String REF_ELEMENT = ref; . public static final String DEFAULT_LAZY_INIT_ATTRIBUTE = default-lazy-init; public static final String DEFAULT_MERGE
29、_ATTRIBUTE = default-merge; public static final String DEFAULT_AUTOWIRE_ATTRIBUTE = default-autowire; public static final String DEFAULT_DEPENDENCY_CHECK_ATTRIBUTE = default-dependency-check; public static final String DEFAULT_AUTOWIRE_CANDIDATES_ATTRIBUTE = default-autowire-candidates; public static final String DEFAULT_INIT_METHOD_ATTRIBUTE = default-init-method; public static final String DEFAULT_DESTROY_METHOD_ATTRIBUTE = default-destroy-method; . private final XmlR
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1