Spring源码--BeanFactory


github地址:
https://github.com/a18792721831/studySpringSource.git

BeanFactory

Spring Ioc 是一个管理Bean的容器,在Spring的定义中,他要求所有的Ioc容器都需要实现接口BeanFactoryBeanFactory是一个顶级容器接口。

public interface BeanFactory {
    
    

    // 前缀
	String FACTORY_BEAN_PREFIX = "&";

    // 根据名称获取bean
	Object getBean(String name) throws BeansException;

    // 根据名称获取bean,返回指定类型
	<T> T getBean(String name, Class<T> requiredType) throws BeansException;

    // 根据名称获取bean,使用指定的参数初始化
	Object getBean(String name, Object... args) throws BeansException;

    // 根据类型获取bean
	<T> T getBean(Class<T> requiredType) throws BeansException;

    // 根据类型获取bean,使用指定的参数初始化
	<T> T getBean(Class<T> requiredType, Object... args) throws BeansException;

    // 根据类型获取bean提供者
	<T> ObjectProvider<T> getBeanProvider(Class<T> requiredType);

	<T> ObjectProvider<T> getBeanProvider(ResolvableType requiredType);

    // 是否存在指定名称的bean
	boolean containsBean(String name);

    // 指定的bean是否是单例
	boolean isSingleton(String name) throws NoSuchBeanDefinitionException;

    // 指定的bean是否是原型
	boolean isPrototype(String name) throws NoSuchBeanDefinitionException;

    // 是否类型匹配
	boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;

	boolean isTypeMatch(String name, Class<?> typeToMatch) throws NoSuchBeanDefinitionException;

    // 获取指定bean的类型
	@Nullable
	Class<?> getType(String name) throws NoSuchBeanDefinitionException;

	@Nullable
	Class<?> getType(String name, boolean allowFactoryBeanInit) throws NoSuchBeanDefinitionException;

    // 获取bean的别名
	String[] getAliases(String name);

}

BeanFactory中含有多个getBean方法,这是Ioc容器最重要的方法之一,主要是从Ioc容器中获取Bean。这些getBean的方法中有按类型、按名称获取bean,这也是说,在Spring Ioc容器中,允许按照名称或者类型获取bean.

由于BeanFacttory的功能还不够强大,因此Spring在BeanFactory的基础上,还设计了更为高级的接口:ApplicationContext,这是BeanFactory的子接口之一,在Spring的体系中BeanFactoryApplicationContext是最为重要的接口设计,实际使用的大部分Spring Ioc容器是ApplicationContext接口的实现类。

ApplicationContext

ApplicationContext接口通过集成上级接口,进而集成BeanFactory接口。在BeanFactory的基础上,扩展了消息国际化接口(MessageSource)和资源模式解析接口(ResourcePatternResolver)。

容器的基本使用

我们在idea中创建一个springboot的工程,只需要lombok和web的starter即可。(gradle)

image-20200820193932622

我们这里创建了spring boot的工程,但是只是使用gradle自动下载spring的依赖即可。

还记得一个spring项目是如何创建的吗?

复习一下:

spring–hello~!(如何搭建一个spring项目)

spring核心容器创建的两种方式

省去依赖包,我们创建一个spring的项目

image-20200820194405030

新增bean

image-20200820194429874

新增beans.xml

image-20200820194453702

然后注释掉spring boot中原来的代码,添加我们的代码

image-20200820194528160

运行

在这里插入图片描述

可以看到,最终,我们打印出了people的name.也就是说,通过XmlBeanFactory加载了我们制定的配置文件后,使用指定的配置文件,创建了我们需要的Ioc容器。最后我们可以通过名字获取bean。

XmlBeanFactory源码

虽然XmlBeanFactory基本上没有人在使用,而且也被标记为废弃了,但是,作为我spring入门的一个方法,我还是想看看其具体的实现。

这是XmlBeanFactory的UML图:

我们可以看到,XmlBeanFactory直接继承DefaultListableBeanFactory,而DefaultListableBeanFactory上面又有非常多的继承关系。

  • AliasRegistry:定义对alias的简单增删改等操作。
  • SimpleAliasRegistry:主要使用Map作为alias的缓存,并对接口AliasRegistry进行实现。
  • SingletonBeanRegistry:定义对单例的注册及获取。
  • BeanFactry:定义获取bean及bean的各种特性。
  • DefaultSingletonBeanRegistry:对接口SingletonBeanRegistry的实现。
  • HierarchicalBeanFactory:继承BeanFactory,也就是在BeanFactory定义的功能的基础上增加了对parentFactory的支持。
  • BeanDefinitionRegistry:定义对BeanDefinition的各种增删改操作。
  • FactoryBeanRegistrySupport:在DefaultSingletonBeanRegistry基础上增加了对BeanFactory的特殊处理。
  • ConfigurableBeanFactory:提供配置Factory的各种方法。
  • ListableBeanFactory:根据各种条件获取bean的配置清单。
  • AbstractBeanFactory:综合FactoryBeanRegistrySupportConfigurableBeanFactory的功能。
  • AutowireCapableBeanFactory:提供创建bean、自动注入、初始化以及应用bean的后处理器。
  • AbstractAutowireCapableBeanFactoryA:综合AbstractBeanFactory并对接口AutowireCapableBeanFactory进行实现。
  • ConfigurableListableBeanFactory:BeanFactory配置清单,指定忽略类型及接口等。
  • DefaultListableBeanFactory:综合上述全部功能,主要是对Bean进行注册后的处理。

XmlBeanFactoryDefaultListableBeanFactory进行了扩展,从Xml文档中读取BeanDefinition,对于注册和获取都是使用的父类继承的方法。

image-20200820202243293

XmlBeanDefinitionReader

这是XmlBeanDefinitionReader的UML图

这些类主要的操作:

  • ResourceLoader:定义资源加载器,主要应用于根据给定的资源文件地址返回对应的Resource。
  • BeanDefinitionReader:主要定义自语言文件读取并转换为BeanDefinition的各个功能。
  • EnvironmentCapable:定义获取Environment方法。
  • DockumentLoader:定义从资源文件加载到转换为Document的功能。
  • AbstractBeanDefinitionReader:对EnvironmentCapable,BeanDefinitionReader类定义的功能进行实现。
  • BeanDefinitionDocumentReader定义读取Document并注册BeanDefinition功能。
  • BeanDefinitionParserDelegate:定义解析Element的各种方法。

XmlBeanFactory

我们看下XmlBeanFactory的时序图:

在main方法中首先调用ClassPathResource的构造方法来构造Resource资源文件的实例对象,这样后续的资源处理就可以用Resource提供的服务进行操作,有了Resource后,就可以进行XmlBeanFactory的初始化了。

配置文件的封装

Spring的配置文件读取是通过ClassPathResource进行封装的,比如new ClassPathResource("beans.xml")

在java中,将不同来源的资源抽象成URL,通过注册不同的handler(URLStreamHandler)来处理不同来源的资源的读取逻辑,一般handler的类型使用不同的前缀来识别,比如:file:,http:,jar:等。但是URL没有默认定义相对ClassPath或者ServletContext等资源的handler,虽然可以注册自己的URLStreamHandler来解析特定的URL前缀(比如cclasspath:),这样需要了解URL的实现机制,而且URL也没有提供基本方法检查资源是否存在等。所以Spring对内部使用到的资源资源实现了自己的抽象结构:Resource

这是Resource的方法

image-20200822144138299

Resource接口抽象了所有Spring内部使用到的底层资源:File,URL,Classpath等。

定义了3个判断当前资源状态的方法:存在性(exists)、可读性(isReadable)、是否处于打开状态(isOpen)。另外,Resource接口还提供了不同资源到URL、URI、File类型的转换,以及获取lastModified属性、文件名(不带路径信息的文件名,getFilename())的方法。为了便于操作,Resource 还提供了基于当前资源创建一个相对资源的方法:createRelativeO。在错误处理中需要详细地打印出错的资源文件,因而 Resource还提供了 getDescription()方法用于在错误处理中的打印信息。

image-20200822143834013

不同来源的资源文件都有相应的Resource实现:文件(FileSystemResource),ClassPath资源(ClassPathResource),URL资源(UrlResource),InputStream资源(InputStreamResource),Byte数组(ByteArrayResource)等。

具体实现也很简单,ClassPathResource是通过ClassLoader进行读取文件的:

image-20200822145454635

得到了配置流后,就交给了XmlBeanDefinitionReader进行解析。

image-20200822145716503

image-20200822145729279

在初始化父类的时候,忽略装配一些类

image-20200822145953961

加载Bean

  1. 封装资源文件。当进入XmlBeanDefinitionReader后首先对参数Resource使用EncodeResource类进行封装。
  2. 获取输入流。从Resource中获取对应的InputSttream并构造InputSource
  3. 通过构造的InputSource实例和Resource实例继续调用方法doLoadBeanDefinitions

image-20200822152733034

EncodeedResource主要用于对资源文件的编码进行相应的编码处理。

image-20200822154027396

如果设置了编码属性,会使用相应的编码作为输入流的编码。

在这里插入图片描述

这个方法主要是将重新编码的输入流转换为SAX的InputSource对象,同时如果指定了编码,需要设置相关的属性。

在这里插入图片描述

这个方法处理了两件事情:

  • 加载XML文件,得到对应的Document.
  • 根据返回的Document注册bean

XML的验证模式

XML文件的验证模式保证了XML文件的正确性,而比较常用的验证模式有两种:DTD和XSD。

image-20200822181516391

image-20200822181600969

DTD

DTD(Document Type Dedfinition)即文档类型定义,是一种XML约束模式语言,是XML文件的验证机制,属于XML文件组成的一部分。DTD是一种保证XML文档格式正确的有效方法,可以通过比较XML文档和DTD文件来看文档是否符合规范,元素和标签使用是否正确。一个DTD文档包含:元素的定义规则,元素间关系的定义规则,元素可以使用的属性,可以使用的实体或符号规则。

要使用DTD验证模式的时候需要在XML文件的头部声明:

image-20200822172452919

DTD文件里面是一些ENTITY节点

image-20200822172528742

XSD

XML Schema语言就是XSD(XML Schema Definition)。Xml Schema描述了XML文档的结构。可以用一个指定的XML Schema来验证某个XML文档,已检查改XML文档是否符合其要求。文档设计者可以通过过XML Schema指定一个XML文档所允许的结构和内容,并可以据此检查一个XML文档是否是以有效的。XML Schema本身是一个XML文档,他符合XML语法结构,可以使用通用的XML解析器解析它。

image-20200822181110255

在使用XML Schema文档对XML实例文档进行检验,除了要声明空间外(xmlns=....),还必须指定该名称空间锁对应的XML Schema文档的存储位置。通过schemaLocation属性来指定名称空间所对一样的XML Schema文档的存储位置。它包含两个部分,一部分是名称空间的URL,另一部分就是该名称空间所表示的XML Schema文件位置或者URL地址。

获取Document

image-20200822181621954

调用了DocumentLoader接口的方法:

image-20200822181704320

这个接口只有一个实现类DefaultDocumentLoader

image-20200822182350576

BeanDefinitions

将配置文件转换为Document后,就会根据Document对象进行注册Bean.

image-20200822182535309

注册bean:

image-20200822183351796

首先通过反射获取BeanDefinitionDocumentReader的对象。

image-20200822183516072

然后记录下本次注册前,已经有多少个bean被注册了。

然后调用documentReader对象进行注册。

image-20200822183726851

使用的还是默认实现

image-20200822183745063

在使用documentReader进行读取时,首先读取的是root节点。

image-20200822183936937

接下来就是解析的核心逻辑了:

在这里插入图片描述

首先处理profile

image-20200822184440549

解析bean就是这里了

image-20200822184809167

image-20200822185320840

猜你喜欢

转载自blog.csdn.net/a18792721831/article/details/108172805