Spring 源码深入解析(1)之bean容器的基本实现(一)

首先感谢 《Spring源码深度解析》郝佳,让我对spring源码有了更深的理解,本篇文章主要是对《Spring源码深度解析》解读的笔记以及自己对书本解读后的理解

 

1.DefaultListtableBeanFactory(bean组件的两个核心类)

 

    XmlBeanFactory继承DefaultListtableBeanFactory,DefaultListtableBeanFactory是整个bean加载的核心,与XmlBeanFactory不同的是XmlBeanFactory中使用了自定义的XML读取器XmlBeanDefintion实现了个性化的BeanDefintion读取。

    DefaultListtableBeanFactory继承了AbstractAutowireCapableBeanFactoty 并实现了 ConfigurableListtableBeanFactory以及BeanDefinitionRegistry接口

ConfigurableListtableBeanFactory 的层次结构图如下:

    a、AliasRegistry:定义对alias的简单增删改操作

    b、SimpleAliasRegistry:主要使用Map作为alias的缓存,并对接口AliasRegistry进行实现

    c、SingLetonBeanRegisty:定义对单例的注册以及获取

    d、BeanFactory:定义获取bean及bean的各种属性

    e、DefaultSingletonBeanRegistry:对接口SingletonBeanRegistry和函数的实现

    f、FactoryBeanRegistySupport:在DefaultSingletonBeanRegistry基础上增加对Factory的特殊处理

    g、ConfigurableBeanFactory:提供配置Factory的各种方法

    h、ListableBeanFactory:根据各种条件获取bean的配置清单

    i、AbstractBeanFactory:综合AbstractBeanFactory 并对接口Autowire CapableBeaFactory进行实现

    j、ConfigurableListableBeanFactory:BeanFactoryb配置清单,指定忽略类型及接口等

    k、DefaultListtableBeanFactory:综合上面的所有功能

 

2.XmlBeanDefinitionReader(bean组件的两个核心类)

    XML配置文件的读取Spring中重要的功能。可以从XmlBeanDefinitionReader中梳理资源文件读取、解析以及注册;各类用法如下

    a、ResourceLoader:定义资源加载器、主要应用于根据给定的资源文件地址返回的Resource

    b、BeanDefinitionReader:主要定义资源文件读取并转换为BeanDefinition 的各个功能

    c、EnvironmentCapable:定义获取Environment 方法

    d、DocumentLoader:定义资源文件加载到转换为Document的功能

    e、AbstractBeanDefinitionReader:对EnvironmentCapable、BeanDefinitionReader类定义的功能进行实现

    f、BeanDefinitionDocumentReader:定义读取Document并注册BeanDefinition功能

    g、BeanDefinitionParserDelegate:定义解析Element的各种方法

 

    整个XML配置文件读取数据的大致流程(在XmlBeanDefinitionReader包含的几个处理)

    a、通过继承自AbstractBeanDefinitionReader中的方法,使用ResourceLoader将资源文件路径转换为Resource文件

    b、通过Document将Resource文件转换为Document文件

    c、通过BeanDefinitionReader的实现类DefaultBeanDefinitionReader对Element·进行解析

 

 3.容器的基础XmlBeanFactory

 

    a、配置文件封装

Spring的配置文件读取是通过ClassPathResource进行封装的,在java中将不同来源的资源抽象成URL,通过注册不同的handle来处理不同来源的资源的读取逻辑,

handle的类型通过使用不通的前缀(协议)来识别,如“file”、“http”、“jar”等。而URL没有默认定义的相对Classpath或ServletContext等资源的handler,需要了解

URL实现机制来自己注册URLStreamHandler来解析特定的URL前缀。因此Spring对其内部使用到的资源实现了自己的抽象结构:Resource接口来封装底层资源

    源码:

    public interface InputStreamSource {

        //返回一个新的InputStream对象

public abstract InputStream getInputStream() throws IOException;

    }

    public interface Resource extends InputStreamSource {

        //是否存在

       public abstract boolean exists();

        //是否可读

        public abstract boolean isReadable();

        //是否打开

       public abstract boolean isOpen();

        //获取URL

        public abstract URL getURL() throws IOException;

        //获取URI

       public abstract URI getURI() throws IOException;

        //获取File

       public abstract File getFile() throws IOException;

        //获取长度

       public abstract long contentLength() throws IOException;

        //获取lastModified属性

        public abstract long lastModified() throws IOException;

        //基于当前资源创建一个相对资源

       public abstract Resource createRelative(String s) throws IOException;

       //获取文件名

      public abstract String getFilename();

      //错误处理中打印信息

      public abstract String getDescription();

    }

    对于不同的资源都有不同的实现:如文件、classpath资源等,Resource完成对配置文件进行封装后读取的工作全权交给了XmlBeanDefinitionReader

    

    b、加载Bean

      在XmlBeanFactory的初始化有多个方法,在其中有一个使用Resource实例作为构造函数参数的方法,源码如下

     public XmlBeanFactory(Resource resource) throws BeansException {

         this(resource, null);

    }

    public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {

        super(parentBeanFactory);

       //整个资源加载的切入点

      this.reader.loadBeanDefinitions(resource);

     }

   //构造函数中this.reader.loadBeanDefinitions(resource);是资源加载的真正实现,在这之前还调用了父类构造方法初始化过程super(parentBeanFactory);

    public AbstractAutowireCapableBeanFactory() {

         super();

        //自动装配功能

         ignoreDependencyInterface(BeanNameAware.class);

         ignoreDependencyInterface(BeanFactoryAware.class);

         ignoreDependencyInterface(BeanClassLoaderAware.class);

     }

      this.reader.loadBeanDefinitions(resource);整个资源加载的切入点方法的时序

      ①:封装资源文件。进入XmlBeanDefinitionReader后首先对Resource使用EncodeResource的Resource类进行封装(编码)

      public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {

         return loadBeanDefinitions(new EncodedResource(resource));

      }

     EncodeResource主要用于对文件的编码进行处理,其中主要体现在getReader()方法中

     public Reader getReader() throws IOException {

      if (this.charset != null) {

          return new InputStreamReader(this.resource.getInputStream(), this.charset);

     }

    else if (this.encoding != null) {

        return new InputStreamReader(this.resource.getInputStream(), this.encoding);

     }

    else {

      return new InputStreamReader(this.resource.getInputStream());

    }

    }

    ②:获取输入流:从Resource中获取对应的InputStream并构造InputSource

    ③:在构造InputSource 实例个Resource实例继续调用都LoadBeanDefinition

     LoadBeanDefinition方法是真正的数据准备阶段,源码如下

    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();

        //在得到经过EncodeResource封装过的Resource来获取InputStream

   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();

   }

  }

}

doLoadBeanDefinitions方法做了三件事

①:获取XML文件的验证模式

②:加载XML,获取Document对象

③:根据返回的Document注册Bean

源码如下

protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)

throws BeanDefinitionStoreException {

   try {

    //得到Document 对象

    Document doc = doLoadDocument(inputSource, resource);

    //注册Bean

    return registerBeanDefinitions(doc, resource);

  }

    catch (BeanDefinitionStoreException ex) {

    throw ex;

 }

   catch (SAXParseException ex) {

   throw new XmlBeanDefinitionStoreException(resource.getDescription(),

   "Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex);

}

catch (SAXException ex) {

    throw new XmlBeanDefinitionStoreException(resource.getDescription(),

    "XMLdocument from " + resource + " is invalid", ex);

}

catch (ParserConfigurationException ex) {

    throw new BeanDefinitionStoreException(resource.getDescription(),

   "Parser configuration exception parsing XML from " + resource, ex);

}

catch (IOException ex) {

   throw new BeanDefinitionStoreException(resource.getDescription(),

  "IOException parsing XML document from " + resource, ex);

}

catch (Throwable ex) {

   throw new BeanDefinitionStoreException(resource.getDescription(),

  "Unexpected exception parsing XML document from " + resource, ex);

}

}

//加载XML,返回Document对象

protected Document doLoadDocument(InputSource inputSource, Resource resource) throws Exception {

    return this.documentLoader.loadDocument(inputSource, getEntityResolver(), this.errorHandler,

    getValidationModeForResource(resource), isNamespaceAware());

}

//得到验证模式

protected int getValidationModeForResource(Resource resource) {

   int validationModeToUse = getValidationMode();

   if (validationModeToUse != VALIDATION_AUTO) {

       return validationModeToUse;

   }

    int detectedMode = detectValidationMode(resource);

    if (detectedMode != VALIDATION_AUTO) {

        return detectedMode;

    }

    // Hmm, we didn't get a clear indication... Let's assume XSD,

    // since apparently no DTD declaration has been found up until

    // detection stopped (before finding the document's root tag).

    return VALIDATION_XSD;

}

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值