"Spring Source depth analysis" two

The second chapter: the basic realization of the container

2.1 Basic Usage

First we define a Bean :( assuming a bean package)

"Spring Source depth analysis" two

Then define the configuration file:

"Spring Source depth analysis" two

Test categories:

"Spring Source depth analysis" two

Of course, this is not enterprise-class usage, here is just learning to analyze its implementation

2.2 Functional Analysis

FIG Code above three functions as follows:

1. Read the configuration file beanFactocyTest.xml

2. Find the class corresponding to the configuration according beanFactocyTest.xml configuration, and instantiate

3. Call the object after instantiation

Can guess that a total of three categories: ConfigReader for reading the configuration file, for reflecting ReflectionUtil instantiate configuration bean, App logic for completing the entire series

Chart:

"Spring Source depth analysis" two

Here's a look at the implementation of Sping

2.3 org.springframework.beans initial introduction

2.3.1 Project directory

"Spring Source depth analysis" two

 

2.3.2 The two core classes

2.3.2.1 DefaultListableBeanFactory

public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
        implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable

The entire core of the bean is loaded, the default is registered and loaded Spring bean implementation

XmlBeanFactory be inherited, use the self-defined XML reader XmlBeanDefinitionReader realized BeanDefinitionReader read personalized, primarily reader attributes of the resource file for reading and registration, and the registration and acquisition method of the bean are using DefaultListableBeanFactory

FIG class structure: idea to open the F4

"Spring Source depth analysis" two

FIG its container loads Class effect:

"Spring Source depth analysis" two

2.3.2.2 XmlBeanDefinitionReader

That is, after 2.3.2.1 explained in a custom XML reader XmlBeanFactory use of resources to achieve the reading of the documents, analysis and registration, namely Resource related classes completed the package configuration file, it reads the configuration file will be completed jobs

Profile Class FIG its role read:

"Spring Source depth analysis" two

 

XmlBeanDefinitionReader处理流程:
1.通过继承的AbstractBeanDefinitionReader的方法,使用ResourLoader将资源文件路径转换为对应的Resouce文件
2.通过DocumentLoader将Resouce文件转换为Document文件
3.通过DefaultBeanDefinitionDocumentReader对Document进行解析,并使用BeanDefinitionParserDelegate进行解析

2.4 2.1中代码的功能实现

2.4.1 BeanFactory bf = new XmlBeanFactory(new ClassPathResource("beanFactoryTest.xml"));

处理时序图:

"Spring Source depth analysis" two

流程:首先创建和封装Resource对象,传给XmlBeanFactory后,调用loadBeanDefinitions,最终返回BeanFactory对象。

那么,如何封装Resource资源呢?

2.4.1.1 封装Resource资源

ClassPathResource:封装配置文件,使用Resource接口封装底层资源,如File、URL、Classpath等
底层资源注:不同来源的资源为URL,通过注册不同的handler(如URLStreamHandler)来处理不同来源的读取逻辑;handler使用前缀+协议(Protocol)属性来识别不同来源,如"file:""http:""jar:"等

Resource相关接口:

"Spring Source depth analysis" two

不同来源的资源对应的Resource实现:

"Spring Source depth analysis" two

getInputStream方法:

从实现类的类名可以推出,实现类组合了其类名的类,如下两个例子:
ClassPathResource:通过class或classLoader提供的底层方法进行调用,组合了path

"Spring Source depth analysis" two

FileSystemResource:使用FileInputStream对文件进行实例化,组合了file

"Spring Source depth analysis" two

技巧:日常开发中,可以直接使用Spring提供的类来加载资源,如下图:

"Spring Source depth analysis" two

2.4.1.2 流程的其他步骤实现

XmlBeanFactory初始化,使用Resourse示例作为构造方法参数:

"Spring Source depth analysis" two

首先会调用其间接父类AbstractAutowireCapableBeanFactory的构造方法:

"Spring Source depth analysis" two

其ignoreDependencyInterface方法主要功能是忽略给定接口的自动装配功能,为什么要有这个方法呢?

"Spring Source depth analysis" two

接着回到XmlBeanFactory构造方法的loadBeanDefinitions(resource),这个方法是整个资源加载的切入点

时序图:

"Spring Source depth analysis" two

其处理过程如下:(其中2.通过SAX读取XML文件来准备InputSource)

"Spring Source depth analysis" two

EncodedResource封装了有编码的InputStreamReader
构造好EncodedResource后,就进入了真正的数据准备阶段loadBeanDefinitions,即"处理时序图"所示的第三阶段
这个方法的逻辑核心部分为doLoadBeanDefinitions,做了下列三件事情:

"Spring Source depth analysis" two

这三件事情,我们来逐步分析

1.获取对XML文件的验证模式:getValidationModeForResource (Resource resource)
a 常用的验证模式:DTD、XSD
可以通过比较XML文档和DTD 文件来看文档是否符合规范,元素和标签使用是否正确
也可以用一个指定的XML Schema(本身也是XML)来验证某个XML 文档, 以检查该XML文档是否符合其要求
b 验证模式的读取,可以通过setValidationMode进行设定验证模式
流程代码:

"Spring Source depth analysis" two

detectValidationMode方法使用委派模式,委托给了XmlValiadationModeDetector(通过组合此类)的validationModeDetector方法来实现自动检测验证模式:
判断是否包含DOCTYPE ,如果包含就是DTD ,否则就是XSD

2.加载XML文件,并得到对应的Document:loadDocument

同样地,XmlBeanFactoryReader将文档读取任务委托给了DocumentLoader接口,真正调用的实现类为DefaultDocumentLoader,通过SAX来解析XML文档(相同的套路,首先创建DocumentBuilderFactory ,再通
过DocumentBuilderFactory创建DocumentBuilder, 进而解析inputSource来返回Document 对象。)
loadDocument方法中涉及一个参数EntityResolver,下面解释一下

2.1 EntityResolver

可以提供一个如何寻找DTD声明的方法,即由程序来实现寻找DTD声明的过程,比如我们将DTD文件放到项目中某处,在实现时直接将此文档读取并返回给SAX 即可。这样就避免了通过网络来寻找相应的声明,加快速度。
2.1.1 通过getEntityResolver方法获取

"Spring Source depth analysis" two

2.1.2 如何将URL转换为工程对应的地址文件呢?
对不同的验证模式,Spring 使用了不同的解析器解析
比如加载DTD类型的BeansDtdResolver的resolveEntity是直接截取systemld 最后的xx.dtd
然后去当前路径下寻找,而加载XSD类型的PluggableSchemaResolver 类的resolveEntity 是默
认到META-INF/Spring.schemas 文件巾找到systemid 所对应的XSD 文件并加载。

3.根据返回的Document注册Bean信息

拥有Documemt对象时,调用下面方法

public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
    //实例化
    BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
    //记录统计前BeanDefinition的加载个数
    int countBefore = getRegistry().getBeanDefinitionCount();
    //加载注册bean
    documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
    //记录本次加载的BeanDefinition个数
    return getRegistry().getBeanDefinitionCount() - countBefore;
}

@Override
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
    this.readerContext = readerContext;
    doRegisterBeanDefinitions(doc.getDocumentElement());
}

DefaultBeanDefinitionDocumentReader的doRegisterBeanDefinitions(doc.getDocumentElement());真正地开始解析:

protected void doRegisterBeanDefinitions(Element root) {
    //专门处理解析
    BeanDefinitionParserDelegate parent = this.delegate;
    this.delegate = createDelegate(getReaderContext(), root, parent);

    if (this.delegate.isDefaultNamespace(root)) {
        //处理profile属性
        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.isDebugEnabled()) {
                    logger.debug("Skipped XML bean definition file due to specified profiles [" + profileSpec +
                            "] not matching: " + getReaderContext().getResource());
                }
                return;
            }
        }
    }
    //解析前处理,留给子类实现
    preProcessXml(root);
    //解析
    parseBeanDefinitions(root, this.delegate);
    //解析后处理,留给子类实现
    postProcessXml(root);

    this.delegate = parent;
}

涉及模板方法模式,DefaultBeanDefinitionDocumentReader的子类如果需要在Bean解析前后做一些处理的话,那么只需要重写preProcessXml(root)和postProcessXml(root))

而parseBeanDefinitions则对不同类Bean分别做不同的处理

/**
 * 处理两大类Bean声明
 * 一个是默认的,如:<bean id=”test” class=”test.TestBean” />
 * 另一类就是自定义的,如:<tx :annotation-driven/>
 * @param root
 * @param delegate
 */
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);
    }
}

 

 

总结

DefaultListableBeanFactory和XmlBeanDefinitionReader是Spring容器基本实现的两个核心类

DefaultListableBeanFactory is a core part of the whole bean loaded, the default is registered and loaded Spring bean implementation

XmlBeanDefinitionReader is a custom XML reader XmlBeanFactory use of resources to achieve the reading of the documents, analysis and registration

Creating the BeanFactory procedures: First, create and package Resource objects, passed after XmlBeanFactory, call loadBeanDefinitions, eventually returning BeanFactory object.

Guess you like

Origin www.cnblogs.com/mxb0611/p/11926856.html