01_spring源码分析-XmlBeanFactory

Spring源码分析之BeanFactory

献自己:

  枯燥无味的学习之路有时真的是无法静下心来苦心钻研;没有掌声,没有鲜花,只有自己内心浮躁不安。

  谨记:戒骄戒躁,潜心求知。


一、工程代码如下:

//实体类
public
class Person { private String name; public String getName() { return "Axuduo"; } public void setName(String name) { this.name = name; } }
//测试类
public
class TestBean { @Test public void getPerson(){ BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("spring-bean.xml")); Person person = (Person) beanFactory.getBean("person"); Assert.assertEquals("Axuduo",person.getName()); } }
//配置文件:spring-bean.xml
<?xml version="1.0" encoding="UTF-8"?> <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="person" class="com.oops.pojo.Person"/> </beans>

二、基础容器XmlBeanFactory

  首先将分析实例化XmlBeanFactory开始;对应代码:

BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("spring-bean.xml"));

  1、封装配置文件  

  时序图如下:

  归纳:测试类首先调用ClassPathResouce的构造函数,构造Resource资源文件的实例对象;将Resource对象传递给XMLBeanFactory进行实例化该对象初始化。

  那么,ClassPathResouce都做了哪些操作呢?

  其实Spring对其内部使用到的资源实现了自己的抽象结构,Resource接口封装底层资源。其中InputStreamSource接口封装任何可能返回InputStream的类,它只定义了一个方法getInputStream方法,该方法返回一个InputStream对象。

  在得到InputStream后就可以利用Resource及其子类为我们提供的特性进行后续开发了。有了Resource接口便可以对所有资源文件统一处理了。具体Resource接口如下:

public interface Resource extends InputStreamSource {

    /**
     * 是否存在*/
    boolean exists();
    /**
     * 可读性*/
    default boolean isReadable() {
        return exists();
    }
    /**
     * 是否打开状态*/
    default boolean isOpen() {
        return false;
    }
    /**
     * 是否是一个文件*/
    default boolean isFile() {
        return false;
    }
    /**
     * 获取URL资源*/
    URL getURL() throws IOException;
    /**
     * 获取URI资源*/
    URI getURI() throws IOException;
    /**
     * 获取文件资源*/
    File getFile() throws IOException;
    /**
     * 取消读取*/
    default ReadableByteChannel readableChannel() throws IOException {
        return Channels.newChannel(getInputStream());
    }
    /**
     * 内容长度*/
    long contentLength() throws IOException;
    /**
     * 最后修改时间*/
    long lastModified() throws IOException;
    /**
     * 创建一个相对资源*/
    Resource createRelative(String relativePath) throws IOException;
    /**
     * 获取文件名*/
    @Nullable
    String getFilename();
    /**
     * 获取文件描述*/
    String getDescription();
}

  当通过Resource相关类完成了对配置文件进行封装后;配置文件的读取工作就全部交给XmlBeanFactory来处理了。

  2、XmlBeanFactory

  XmlBeanFactory通过封装后的Resource进行实例化对象。代码如下:

public class XmlBeanFactory extends DefaultListableBeanFactory {
    private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);
    /**
     * 构造函数需要:Resource 对象*/
    public XmlBeanFactory(Resource resource) throws BeansException {
        this(resource, null);
    }
    /**
     * 待自身构造调用;委派至XMLBeanDeinitionReader*/
    public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
        super(parentBeanFactory);          // 注意父类中执行了两个或多个类的自动装配功能
        this.reader.loadBeanDefinitions(resource);
    }
}

   3、加载Bean

  首先看一下时序图

  流程梳理:

    1、封装资源文件。当进入XMlBeanDefiinitionReader后首先对参数Resource使用EncodedResource类进行封装。

    2、获取输入流。从Resouce中获取对应的InputStream 并构造InputSource.

    3、通过构造的InputSource实例和Resouce实例继续调用函数doLoadBeanDefinitions.

  EncodeResource主要是对资源文件进行编码处理;如果有指定编码则使用指定编码;没有则采用默认。方法如下

   public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
        return loadBeanDefinitions(new EncodedResource(resource));
    }

  通过上面的对资源文件的处理后将进入最核心的部位了:doLoadBeanDefinitions(InputSource inputSource,Resouce resource)

//代码经过去除catch部位
protected
int doLoadBeanDefinitions(InputSource inputSource, Resource resource)throws BeanDefinitionStoreException { try { Document doc = doLoadDocument(inputSource, resource);   // 将资源文件传缓存 document int count = registerBeanDefinitions(doc, resource);    // 执行注册 if (logger.isDebugEnabled()) { logger.debug("Loaded " + count + " bean definitions from " + resource); } return count; } }

至此可以清晰的看见只有两部操作:1、转换Document;2、执行注册;

到此完成注册流程。

 

posted @ 2019-07-06 22:50  Axuduo  阅读(378)  评论(0编辑  收藏  举报