1. Xml配置文件解析预处理顺序图
1.1. xml配置文件解析预处理顺序

上图展示Spring框架解析xml配置文件,并解析用户在xml配置文件中定义的bean的整个过程:
所有的
ApplicationContext容器(如ClassPathXmlApplicationContext、XmlWebApplicationContext等)启动后,都会执行到AbstractApplicationContext的refresh()模板方法,此方法调用obtainFreshBeanFactory()会调用子类的refreshBeanFactory()方法来获取bean工厂并完成所有bean的解析处理;public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext, DisposableBean { // 步骤1, 调用refresh方法 @Override public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // Prepare this context for refreshing. prepareRefresh(); // Tell the subclass to refresh the internal bean factory. // 步骤2,调用本类的obtainFreshBeanFactory方法 ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // Prepare the bean factory for use in this context. prepareBeanFactory(beanFactory); try { // 此处省略........ } catch (BeansException ex) { // 此处省略........ } finally { // 此处省略........ } } } protected ConfigurableListableBeanFactory obtainFreshBeanFactory() { // 步骤3,调用抽象方法,运行时会调用其子类实现的此方法来加载Bean定义 refreshBeanFactory(); ConfigurableListableBeanFactory beanFactory = getBeanFactory(); if (logger.isDebugEnabled()) { logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory); } return beanFactory; } protected abstract void refreshBeanFactory() throws BeansException, IllegalStateException; }refreshBeanFactory()方法在AbstractApplicationContext的子类AbstractRefreshableApplicationContext中实现,实现的过程是:- 创建一个
DefaultListableBeanFactory对象,这是Spring框架的核心类,Spring 的 Bean 解析和实例化以及后续的使用都跟该类有非常密切的关系。 调用
loadBeanDefinitions(beanFactory)方法加载Bean定义,此方法是一个抽象方法,参数为上一步创建的beanFactory对象,其实现类有XmlWebApplicationContext、AnnotationConfigWebApplicationContext、AbstractXmlApplicationContext、GroovyWebApplicationContext,根据容器的不同,会调用不同子类的实现。上图中使用的是XmlWebApplicationContext类,其它类似。public abstract class AbstractRefreshableApplicationContext extends AbstractApplicationContext { @Override protected final void refreshBeanFactory() throws BeansException { if (hasBeanFactory()) { destroyBeans(); closeBeanFactory(); } try { // 步骤4:创建一个DefaultListableBeanFactory对象 DefaultListableBeanFactory beanFactory = createBeanFactory(); beanFactory.setSerializationId(getId()); customizeBeanFactory(beanFactory); // 步骤5:调用子类的loadBeanDefinitions(beanFactory)方法来加载bean定义 loadBeanDefinitions(beanFactory); synchronized (this.beanFactoryMonitor) { this.beanFactory = beanFactory; } } catch (IOException ex) { throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex); } } protected DefaultListableBeanFactory createBeanFactory() { return new DefaultListableBeanFactory(getInternalParentBeanFactory()); } protected abstract void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException; }接下来我们以
XmlWebApplicationContext类为例,来看一下loadBeanDefinitions(beanFactory)是如何解析并加载bean定义的。
- 创建一个
XmlWebApplicationContext类的loadBeanDefinitions方法会首先创建一个XmlBeanDefinitionReader对象用于XML文件的解析。XmlWebApplicationContext对象还负责设置 XML 配置文件名,默认为/WEB-INF/applicationContext.xml。如果是开发人员定义的配置文件,则可能为多个。loadBeanDefinitions方法会循环所有的配置文件名,使用xmlBeanDefinitionReader来加载Bean定义。
public class XmlWebApplicationContext extends AbstractRefreshableWebApplicationContext {
/** Default config location for the root context */
public static final String DEFAULT_CONFIG_LOCATION = "/WEB-INF/applicationContext.xml";
/** Default prefix for building a config location for a namespace */
public static final String DEFAULT_CONFIG_LOCATION_PREFIX = "/WEB-INF/";
/** Default suffix for building a config location for a namespace */
public static final String DEFAULT_CONFIG_LOCATION_SUFFIX = ".xml";
@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
// 步骤6:Create a new XmlBeanDefinitionReader for the given BeanFactory.
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
// Configure the bean definition reader with this context's
// resource loading environment.
beanDefinitionReader.setEnvironment(getEnvironment());
beanDefinitionReader.setResourceLoader(this);
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
// Allow a subclass to provide custom initialization of the reader,
// then proceed with actually loading the bean definitions.
initBeanDefinitionReader(beanDefinitionReader);
// 步骤7:调用本类loadBeanDefinitions方法
loadBeanDefinitions(beanDefinitionReader);
}
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws IOException {
String[] configLocations = getConfigLocations();
if (configLocations != null) {
// 步骤8:循环配置文件路径,调用XmlBeanDefinitionReader.loadBeanDefinitions方法加载Bean定义
for (String configLocation : configLocations) {
reader.loadBeanDefinitions(configLocation);
}
}
}
/**
* The default location for the root context is "/WEB-INF/applicationContext.xml",
* and "/WEB-INF/test-servlet.xml" for a context with the namespace "test-servlet"
* (like for a DispatcherServlet instance with the servlet-name "test").
*/
@Override
protected String[] getDefaultConfigLocations() {
if (getNamespace() != null) {
return new String[] {DEFAULT_CONFIG_LOCATION_PREFIX + getNamespace() + DEFAULT_CONFIG_LOCATION_SUFFIX};
}
else {
return new String[] {DEFAULT_CONFIG_LOCATION};
}
}
beanDefinitionReader会通过JAXP方式解析 XML 配置文件为Document对象doc,Spring 框架对 XML 配置文件的处理即转化为对 Java 对象(Document) 的处理。XmlBeanDefinitionReader会创建两个对象:DefaultBeanDefinitionDocumentReader对象documentReader和XmlReaderContext对象readerContext,最终通过documentReader.registerBeanDefinitions(doc, createReaderContext(resource));方法来注册Beanpublic class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader { /** * Load bean definitions from the specified XML file. * @param resource the resource descriptor for the XML file * @return the number of bean definitions found * @throws BeanDefinitionStoreException in case of loading or parsing errors */ @Override public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException { return loadBeanDefinitions(new EncodedResource(resource)); } public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException { Assert.notNull(encodedResource, "EncodedResource must not be null"); if (logger.isInfoEnabled()) { logger.info("Loading XML bean definitions from " + encodedResource.getResource()); } Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get(); if (currentResources == null) { currentResources = new HashSet<EncodedResource>(4); this.resourcesCurrentlyBeingLoaded.set(currentResources); } if (!currentResources.add(encodedResource)) { throw new BeanDefinitionStoreException( "Detected cyclic loading of " + encodedResource + " - check your import definitions!"); } try { InputStream inputStream = encodedResource.getResource().getInputStream(); try { InputSource inputSource = new InputSource(inputStream); if (encodedResource.getEncoding() != null) { inputSource.setEncoding(encodedResource.getEncoding()); } return doLoadBeanDefinitions(inputSource, encodedResource.getResource()); } finally { inputStream.close(); } } catch (IOException ex) { throw new BeanDefinitionStoreException( "IOException parsing XML document from " + encodedResource.getResource(), ex); } finally { currentResources.remove(encodedResource); if (currentResources.isEmpty()) { this.resourcesCurrentlyBeingLoaded.remove(); } } } protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException { try { // 步骤9:创建一个Document对象 Document doc = doLoadDocument(inputSource, resource); // 步骤10:注册BeanDefinition return registerBeanDefinitions(doc, resource); } // 省略一堆的catch语句 } public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException { // 步骤11:创建`DefaultBeanDefinitionDocumentReader` 对象 `documentReader` BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader(); int countBefore = getRegistry().getBeanDefinitionCount(); // 步骤13:调用`DefaultBeanDefinitionDocumentReader`类的`registerBeanDefinitions`方法来加载Bean documentReader.registerBeanDefinitions(doc, createReaderContext(resource)); return getRegistry().getBeanDefinitionCount() - countBefore; } // 步骤12:创建`XmlReaderContext`对象 public XmlReaderContext createReaderContext(Resource resource) { return new XmlReaderContext(resource, this.problemReporter, this.eventListener, this.sourceExtractor, this, getNamespaceHandlerResolver()); } }DefaultBeanDefinitionDocumentReader类注册Bean定义步骤:- 获取Document的root节点
- 调用方法
doRegisterBeanDefinitions(root) - 创建一个
BeanDefinitionParserDelegate对象 - 调用方法
parseBeanDefinitions(root, this.delegate);解析xml节点 - 循环所有root子节点,如果是默认命名空间,调用
`解析节点,否则调用delegate.parseCustomElement(ele)`解析自定义命名空间。
```java
public class DefaultBeanDefinitionDocumentReader implements BeanDefinitionDocumentReader {
@Override
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
this.readerContext = readerContext;
logger.debug("Loading bean definitions");
// 步骤14:创建xml root元素
Element root = doc.getDocumentElement();
// 步骤15:调用doRegisterBeanDefinitions方法
doRegisterBeanDefinitions(root);
}
protected void doRegisterBeanDefinitions(Element root) {
BeanDefinitionParserDelegate parent = this.delegate;
// 步骤16:创建BeanDefinitionParserDelegate对象delegate
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)) {
if (logger.isInfoEnabled()) {
logger.info("Skipped XML bean definition file due to specified profiles [" + profileSpec +
"] not matching: " + getReaderContext().getResource());
}
return;
}
}
}
preProcessXml(root);
// 步骤18:调用parseBeanDefinitions(root, this.delegate)
parseBeanDefinitions(root, this.delegate);
postProcessXml(root);
this.delegate = parent;
}
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;
// 步骤19:默认命名空间解析
if (delegate.isDefaultNamespace(ele)) {
parseDefaultElement(ele, delegate);
}
// 步骤20:非默认命名空间解析
else {
delegate.parseCustomElement(ele);
}
}
}
}
else {
delegate.parseCustomElement(root);
}
}
// <bean/>元素定义
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";
public static final String ALIAS_ATTRIBUTE = "alias";
public static final String IMPORT_ELEMENT = "import";
public static final String RESOURCE_ATTRIBUTE = "resource";
public static final String PROFILE_ATTRIBUTE = "profile";
```