Spring在创建Bean的过程中,其中一种方式是通过读取XML配置文件,同时XML配置文件,可以配置事务,切面,Bean的初始化等一些列操作,但是Spring是如何读取配置文件,如下:

1.配置文件的读取过程:

启动类创建Bean的代码为:

public class App 
{
    public static void main( String[] args )
    {
        BeanFactory bf = new XmlBeanFactory(new ClassPathResource("application.xml"));
        People p =(People) bf.getBean("people");
        System.out.println("the name is : " + p.getName());
    }
}

XML中的配置为:

<?xml version="1.0" encoding="UTF-8"?>
<!--suppress ALL -->
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="people" class="com.dong.bean.People">
        <property name="age" value="26"></property>
        <property name="name" value="Liudong"></property>
    </bean>
</beans>

2.SpringBean配置文件解读:

(以XMLBeanFactory方式获取)

  1. new ClassPathResource("application.xml");

ClassPathResource

解析:

application.xml为Spring的配置文件,配置文件中可以配置Bean,事务,数据库。

ClassPathResource类:将资源抽象成URL,并使用不同的Resource处理类来进行处理。Java中使用内部定义的自己的Resource抽象结构:对于不同的资源文件,使用不同的实现类FileSystemResource,ClassPathResource,UrlResource,InputStream等。

ClassPathResource的继承关系:

ClassPathResource extends AbstractFileResolvingResource;
AbstractFileResolvingResource extends AbstractResource;
AbstractResource implements Resource;
Resource extends InputStreamSource;

Resource

Resource类中定义了资源的基本操作:资源是否存在,是否可读,可打开,获取资源路径,获取文件名;

InputStreamSource

getInputStream()将资源对象转换为输入流,只要得到字节流,就可以获取资源的任何信息;

  1. BeanFactory bf = new XmlBeanFactory(new ClassPathResource("application.xml"));

XmlBeanFactory

解析:

工厂类,继承DefaultListableBeanFactory,XmlBeanFactory使用自定义的XML读取其XmlBeanDefinitionReader.

它的继承关系有:

XmlBeanFactory extends DefaultListableBeanFactory;

XmlBeanFactory使用自定义的XML读取器XmlBeanDefinitionReader,实现个性化的BeanDefinitionReader读取。

DefaultListableBeanFactory

Spring注册,以及加载bean的默认实现;

它的继承关系为

DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory      implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable

AbstractAutowireCapableBeanFactory

功能是忽略给定接口的自定装配功能,当Bean中有属性需要初始化时,就会被自动初始化,但是有时候我们不需要初始化,例如属性实现了BeanNameAware接口。

  1. this(resource, null);
    XmlBeanFactory调用内部的构造器,this(resource, parentBeanFactory null);
public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
        super(parentBeanFactory);
        this.reader.loadBeanDefinitions(resource);
    }
  1. XmlBeanDefinitionReader
    reader是XmlBeanDefinitionReader的实例,

继承关系为:

XmlBeanDefinitionReader extends AbstractBeanDefinitionReader;
AbstractBeanDefinitionReader implements EnvironmentCapable, BeanDefinitionReader;

AbstractBeanDefinitionReader:定义bean的注册,bean的定义;

EnvironmentCapable:所有Spring应用程序上下文都具有EnvironmentCapable功能,并且该接口主要用于在接受BeanFactory实例的框架方法中执行检查,以便与环境进行交互;

BeanDefinitionReader:Bean定义阅读器的接口。使用Resource和String位置参数指定加载方法。

loadBeanDefinitions(resource):用来装载资源文件,调用内部的loadBeanDefinitions.

public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {   return loadBeanDefinitions(new EncodedResource(resource));}
  1. EncodedResource
    用于对文件的编码进行处理,可以通过EncoderResource构造函数,设置相应的文件编码, 同时也可以通过get,set等相应的扩展方法设置相应的编码,以及获取相应编码的Reader对象;
  2. loadBeanDefinitions(new EncodedResource(resource))
    装载编译好的资源,返回doLoadBeanDefinitions(inputSource, encodedResource.getResource());
  3. doLoadBeanDefinitions(inputSource, encodedResource.getResource())
Document doc = doLoadDocument(inputSource, resource);
return registerBeanDefinitions(doc, resource);
  1. Document
    表示的是XML或HTML文档的实例,继承与Node接口,主要方法有获取文档的类型,创建元素,创建文本节点,创建属性,获取文档的id,等等;
  2. doLoadDocument(inputSource, resource)
return this.documentLoader.loadDocument(inputSource, getEntityResolver(), this.errorHandler,getValidationModeForResource(resource), isNamespaceAware());
  1. getEntityResolver()
    EntityResolver 类,提供一个如何寻找DTD声明的方法,它的两个参数:publicId,systemId;
    publicId:被引用的外部实体的公共标识符;如果未提供,则为null。
    systemId:被引用的外部实体的系统标识符;
    SAX是一个用于各种各样的XML解析器(或者其他可以看做XML解析器的解析器)通用接口的实现 ,SAX读取XML文档上的声明,根据声明寻找DTD定义,默认的寻找规则是即通过声明的DTD的URI地址进行下载相应的DTD声明,并进行认证。

补充:DTD:Document Type Definition,文档类型定义,是用来保证XML文档格式正确的有效方法,可以通过比较XML和DTD文件来看文档是否符合规范。

protected EntityResolver getEntityResolver() {
        if (this.entityResolver == null) {
            // Determine default EntityResolver to use.
            ResourceLoader resourceLoader = getResourceLoader();
            if (resourceLoader != null) {
                this.entityResolver = new ResourceEntityResolver(resourceLoader);
            }
            else {
                this.entityResolver = new DelegatingEntityResolver(getBeanClassLoader());
            }
        }
        return this.entityResolver;
    }

Spring默认使用 new DelegatingEntityResolver(getBeanClassLoader());

  1. getValidationModeForResource(resource)
    获取对应资源的验证模式;

验证模式有DTD和XSD.

DTD:Document Type Definition,文档类型定义,是用来保证XML文档格式正确的有效方法,可以通过比较XML和DTD文件来看文档是否符合规范,元素和标签的使用是否正确。

XSD:XML Schema Definition,表述XML的文档结构,可用来验证XML文档.XML本身也是XML文档,可以使用XML解析器去解析它。XML Schema文档时,需要声明命名空间,还需要指定命名空间对应的位置。

  1. 如果设置了验证模式,则使用设定的,没有的话,则使用默认的验证模式;
    至此,loadDocument方法执行完毕,返回Document对象;
  2. registerBeanDefinitions(doc, resource)
    实现Bean的注册;
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
        BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();     
        int countBefore = getRegistry().getBeanDefinitionCount();
        documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
        return getRegistry().getBeanDefinitionCount() - countBefore;
    }

createBeanDefinitionDocumentReader();创建一个BeanDefinitionDocumentReader实例对象;

documentReader.registerBeanDefinitions(doc, createReaderContext(resource));调用registerBeanDefinitions方法,注意:这里的documentReader对象是DefaultBeanDefinitionDocumentReader类的实例对象,调用的也是该实例的registerBeanDefinitions方法;

public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
        this.readerContext = readerContext;
        logger.debug("Loading bean definitions");
        Element root = doc.getDocumentElement();
        doRegisterBeanDefinitions(root);
    }
  1. doRegisterBeanDefinitions(root);
    开始进行解析,
String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);//处理profile属性,

profile是用来进行多环境配置的属性;

preProcessXml(root);//解析前处理
parseBeanDefinitions(root, this.delegate);
postProcessXml(root);//解析后处理

4.parseBeanDefinitions(root, this.delegate);

进行具体的解析;

Element ele = (Element) node;
    if (delegate.isDefaultNamespace(ele)) {
        parseDefaultElement(ele, delegate); //默认
    }
    else {
        delegate.parseCustomElement(ele); //自定义
    }

根据标签是默认标签还是自定义标签,执行不同的解析;