spring容器_Spring容器的基本功能实现

前言

上次给胖子老板老板讲解完自动问答系统的原理后,获得了胖子老板的高度赞赏,正在满心欢喜的时候,胖老板突然又问我,你知道系统中用到的Spring是什么原理吗? 我回答Spring不是春天的意思吗?……..(此时双方沉默了两分钟)。胖老板说,回去吧…….. 经过本喵的彻夜苦读,终于总结出来Spring以下内容。

1.轻描淡写的来一张Spring结构图

d967736774dd00d2607e87ce55179b0e.png

这些模块可以总结为以下几部分:

1.1 Core Container

Core:Container为核心容器,包含有Core、Beans、Context和Expression  Language模块。

其中,Core模块和Bean模块是Spring框架的基础部分,主要实现了控制反转(IOC)的依赖注入(DI)功能。

(1)Core模块主要包含Spring框架基本核心工具,Spring的其他组件都要用到这个包里的工具类。

(2)Beans模块是所有应用都要应用到的,包含访问和配置文件、创建和管理bean以及进行 Inversion of Control/Dependency Injection(Ioc/DI)操作。

(3)Context模块构建与Core和Beans模块基础之上,提供了一种类似于JNDI的注册器框架式的对象访问方法。Context继承了Beans的特性,为Spring核心提供了大量扩展,添加了国际化、时间传播、资源加载和对Context的透明创建的支持。

(4)Expressionn Languag模块提供了强大的表达式语言,用于在运行时查询和操作对象。

w3school中这样描述:https://www.w3cschool.cn/tomcat/4xy31k9e.htmlJNDI提供了一种统一的方式,可以用在网络上查找和访问服务。通过指定一个资源名称,该名称对应于数据库或命名服务中的一个记录,同时返回数据库连接建立所必须的信息。其实说白了JNDI就是提供一种映射。通过资源名映射到实际的配置。

1.2 Data Access/Integration

Data Access/Integration曾包含JDBC、ORM、OXM、JMS和Transaction模块。

(1)JDBC模块提供了一个JDBC抽象层,封装了Spring对JDBC进行数据访问的所有类。

(2)ORM为对象关系映射层。

(3)JMS模块主要包含了一些制造和消费消息的特性。

(4)Transcation模块支持编程和声明式事务管理,这些事务类必须实现特定的接口,并且对所有的POJO透明。

1.3 Web

Web模块是建立在应用程序上下文模块之上,为基于Web的应用程序提供了上下文,提供了基础的面向Web的集成特性。例如,文件上传等。

1.4 AOP

AOP模块提供了一个符合AOP联盟标准的面向切面编程的实现,它可以让你在任何地方定义拦截器和切点。

1.5 Test

Test模块支持使用JUit和TestNG对Spring组件进行测试。

2. 从一个简单的例子开始

1c22334743170ff63b51fca8da38e8f6.png

5297e141dae18df9f9ebe3eeb263d0d6.png

0933d2da228892d4fe3729b7d41b4cd6.png

 相信这个简单的例子只要有一点开发经验的同学都能够看出来。
 首先,把XMl文件使用classPathResource封装成Resource。
  然后,将Resource传入到XmlBeanfactory进行解析,形成Beanfactory。
 最后,通过Beanfactory获取XML文件中配置的实例化类信息。
 主要过程可以分为:
(1)XML封装成Resource.
(2)Resource进行XmlBeanFactory解析,形成BeanFactory。
(3)从BeanFactory获取实例化好的类。
 到这里Spring主要的核心功能就讲完了,简单吧!
 真的就这么简单吗???

3.来看看XmlBeanFactory标签解析的过程

在正式开始之前先来看看Bean的两个核心类介绍DefaultListableBeanFactory和XmlBeanDefinitioReader。

3.1 DefaultListableBeanFactory

XmlBeanFactory继承自DefaultListableBeanfactory,而DefaultListableBeanfactory是整个Bean加载的核心部分,是Spring注册和加载Bean的默认实现,而对于XmlBeanfactory与DefaultListableBeanfactory不同的是,XmlBeanfactory使用了自定义的XML读取器XmlBeanDefinitionReader,实现了个性能化的BeanDefinionReader读取。通过下图可以清晰的了解到DefaultListableBeanFactory的继承结构,简单的介绍下各个组件结构与功能:

87c199f4f40e799795abcc02b28635b1.png

(1)AliasRegistry:定义alias的简单增删改等操作。

ad9fc2a25d70658b1c76189b9a7f249e.png(2)SimpleAliasRegistry:SimpleAliasregistry主要使用aliasMap作为alias的缓存,并对接口AliasRegistry进行实现。

141bed50efee7d6c2c144bcfb742c8c8.png

(3)SingletonBeanRegistry:定义对单例的注册以及获取。

dd02e0259ca1522988e573b9988abaab.png

(4)BeanFactory: BeanFactory定义Bean以及各种Bean的属性。

7548643901fc0165a31c397ddefafdea.png

(5)DefaultSingletonBeanRegistry:对接口SingletonBeanRegistry函数的实现。

f9081a4f2b99bfb701a3b68afbd89c5f.png

(6)BeanDefinitionRegistry:是对BeanDefiition的各种增删改操作。

8ad5b340817daf2b1c4fb4baad0af31f.png

(7)FactoryBeanRegistrySupport :在DefaultSinngletonBeanRegistry基础上增加了对FactoryBean的特殊处理功能。

2c3d4ccbe2a36d66ed70283de23d6bcf.png

(8)ConfigurableBeanFactory: 提供配置Factory的各种方法。

b24d8317b8c7bdc772d74f73b75a0b50.png

(9)ListableBeanfactory:根据各种条件获取bean配置清单。

a181c4301b9c06e50cc9d1d23eabfbee.png

(10)AbstractBeanFactory:综合FactoryBeanRegistrySupport和ConnfigurableBeanFactory 的功能。

695a0c7bab02f0030efc69b5bdc45e52.png

(11)AutowireCapableBeanFactory: 提供创建bean、自动注入、初始化以及应用bean后的处理器。

45872e35513c6ebab6097d4e48f23e78.png

(12)AbstractAutowireCapableBeanFactory:综合AbstractBeanFactory并对接口Autowired Capable  Beanfactory进行实现。

42e4857b7202207e12833c5550aa7fe0.png

(13)ConfigurableListableBeanFactory: Beanfactor配置清单,制定忽略类型和接口等。

a297a36954b2faf4d0f644044be5489b.png

(14) DefaultListableBeanFactory: 综合上面所有功能,主要是对bean注册后的处理。

61ca68623a8b2b938a22cddeb2885dd5.png

3.2 XmlBeanDefinitionReader

XML文件读取是Spring中重要的功能,因为Spring大部分功能都是以配置作为切入点,可以从XmlBeanDefinitionReader中梳理下资源文件的读取、解析以及注册的大致脉络,先来一张XmlBeanDefinnitionReader继承图。

3196d50613a74dd981db5f635eb28656.png

1.通过继承自AbstractBeanDefinitionReader中的方法,将ResourcLoader将资源文件转化为对应的Resource文件。
2.通过对DocumentLoader对Resource文件进行转换,将Resource文件转换为Document文件。
3.通过实现接口BeanDefinitionnDocumentReader的DefaultDefinitionCocumentReader类对Document进行解析,并使用BeanDefinitionParseDelegate对Element进行解析。

SAX是什么?SAX(simple API for XML)是一种XML解析的替代方法。相比于DOM,SAX是一种速度更快,更有效的方法。它逐行扫描文档,一边扫描一边解析。而且相比于DOM,SAX可以在解析文档的任意时刻停止解析,但任何事物都有其相反的一面,对于SAX来说就是操作复杂。

3.3 XmlBeanFactory

XmlBeanFactory对DefaultListableBeanfactory类进行扩展,主要是从XML文档中读取BeanDefinition。

BeanFactory bf=new XmlBeanfactory(new ClassPathResource("beaFactory.xml"));

在上面代码执行过程中,首先调用ClassPathResource的构造函数来构造Resource资源文件的实例对象。这样后续的资源就可以用Resource提供各种资源服务了。当有了Resource后就可以进行XmlBeanFactory的初始化了。那么,问题来了,Resource资源是如何封装的?

Spring配置文件读取时通过ClassPathResource("beanFactoryTest.xml")
在java中,将不同来源的资源抽象成URL,通过注册不同的handler来处理不同资源读取逻辑,一般handler的类型使用不同前缀(协议,Protocol)来识别。,如“file”,"http"."jar"等,然而URL没有默认定义相对Classpath  ServletContext等资源的handler,虽然可以自定义URLStreamHandler来解析特定URl前缀,比如“classpath”然而这需要了解URL机制,而且URL也没有提供基本的方法,如检查当前资源是否存在等方法。因此Spring对其内部使用到的资源 实现了自己的抽象,Resource接口封装底层资源。
Resource可以对所有资源问你件进行统一处理。至于实现,其实非常简单,以getInputStream为;例,CalssPathResource中实现方式便是通过class或者classLoader提供的底层方法进行调用。

有了Resource接口便可以对所有资源文件进行统一管理,实现方式也非常简单,如getInputStram为例,ClassPathResource的实现方式是通过class或者classloader提供的底层方法进行调用,对于FileSystemResource的实现方式更简单,直接使用FileInputStream对文件进行实例化。

了解了Spring将配置文件封装为Resource类型的实例方法后,就开始进行beanDefinition的解析过程,这里分析使用的是Resource作为构造函数对传入参数的解析过程。

6fa64fd349d71cb7d7214302a15a1e21.png

this.reader.loadBeanDefinitions(resource);才是资源加载的真正实现,也是重点分析之一,来看一份时序图。

505d4611f53f9089ac51208d03a4d713.png

首先,封装资源文件,XmlBeanDefinitionReader对参数Resource使用EncodedResource进行封装。然后,获取输入流从Resource中获取相应的InputStream并构造InputSource。最后,通过构造的InputSource实例和Resource实例继续调用函数doLoadBeanDefinitions,doloadBeanDefinition主要做了三件事。(1)获取XML文件的验证模式
(2)加载XML文件,并得到对应的Document.
(3)根据返回的Document注册Bean

3.3.1  XML文件的验证模式a635b69b7c12428549328badda7d3dd0.png

3cb106dc67bc20a80bee7757ca95e589.png


getValidationModeForResource主要是验证XML了文件的正确性

(1)DTD
DTd(Document Type Definnnnition)即文档定义类型,是一种XML约束模式语言,是XML文件的验证 机制,属于XML文件组成的一部分。

(2)XSD
XML Schema(XML Schema Definition)描述了XML文件结构,可以用一个指定的XMLschema来验证某个XML文档,检查XML文档是否符合要求

3.3.2 Document解析

经过了验证模式准备步骤就可以进行Document加载了,DocumentLoader定义了对Document解析的一些方法,具体的实现类是dafaultDocumentLoader,也是使用SAX解析。
SAX解析XML文档的套路大致都查案不多,Spring在这里没有什么特殊的地方,首先创建DocumentBuilderFactory,再通过DocumentBuilderFactory创建DocumentBuilder,进而解析inputSource来返回Document对象。

57d4c84b1c1ff1c7b50775b173c0595e.png

在loadDocument的方法中设计到有一个参数——EntityResolver,那么EntityResolver的作用是什么?由于DTD的资源在网络上,但是由于某些原因可能会出现网络抖动,会延迟DTD资源的加载,我们可以把DTD资源提前下载好存放到enntityResolver中在实现时直接将此文档读取返回SAX即可。这样就避免了通过网络来寻找相应的声明。 3.3.3 Bean注册
当把文件转换为Document后,接下来的提取以及注册bean,当程序已经拥有XML文档文件的Documennt实例对象时,就会引入下面这个方法:

c940abf7a2b5d9898e728ad4fffa0088.png

preProcessXml和postProcessXml是两个空方法,这两个方法是为子类而设计的,如果对模板模式比较熟悉的话,可以看出这就是用的模板方法。

parseBeanDefinnitionn(root,this.delegate)

d58d84644c9fb99cff97e7aecdfc0c09.png

Spring的XML配置有两大类Bean声明,一个是默认的,如
"test" class="test.Testbean">
另一类定义是:
这两种方式的读取以及解析差别是非常大的,根节点或者子节点如果默认是自定义的,那么需要实现一些接口以及配置,对于根节点和子节点如果是默认命名空间的话则采用parseDefaultElement的方法进行解析。否则使用delegate.parsseCustomElement方法对自定义命名空间进行解析。

好了,Spring基本的功能结构和加载过程就先讲解到这,下一期接着讲讲Spring默认标签的解析过程。本文写作过程参考了郝佳大佬的《Spring源码深度解析》,非常感谢。


最近胖虎我新交了一个朋友,爆个照来给大家认识下。

73d4184f7b1a3d3c19b0bb6b67ea4de0.png

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值