更多面试题:面试题内容聚合
一、老规矩,先比比点幺蛾子
作为一个经常使用 Spring 的后端程序员,小编很早就想彻底弄懂整个 Spring 框架了!但它整体是非常大的,所有继承图非常复杂,加上小编修行尚浅,显得力不从心。不过,男儿在世当立志,今天就先从 Spring IOC 容器的初始化开始说起,即使完成不了对整个 Spring 框架的完全掌握,也不丢人,因为小编动手了,稳住,咱能赢!
下面说一些阅读前的建议:
-
1、阅读源码分析是非常无聊的,但既然你进来了,肯定也是对这个东西进行了解,也希望这篇总结能对你有所启发。
-
2、前方高能,文章可能会非常的长,图文并茂。
-
3、阅读前建议你对相关设计模式、软件设计 6 大原则有所了解,小编会在行文中进行穿插。
-
4、小编在读大四,学识尚浅,喜欢专研,如果你发现文章观点有所错误或者与你见解有差异,欢迎评论区指出和交流!
-
5、建议你边看文章的时候可以边在 IDE 中进行调试跟踪
-
6、文章所有 UML 图利用 idea 自动生成,具体生成方法为:
选中一个类名,先ctrl+shift+alt+U,再ctrl+alt+B,然后回车即可
二、文章将围绕什么来进行展开?
不多,就一行代码,如下图:
这句是 Spring 初始化的代码,虽然只有一句代码,但内容贼多!
三、Spring 容器 IOC 有哪些东西组成?
这样子,小编先理清下思路,一步一步来:
-
1、上面那句代码有个文件叫
applicationContext.xml
, 这是个资源文件,由于我们的bean
都在里边进行配置定义,那 Spring 总得对这个文件进行读取并解析
吧!所以 Spring 中有个模块叫Resource
模块,顾名思义,就是资源
嘛!用于对所有资源xml、txt、property
等文件资源的抽象。
下面先贴一张小编生成的类图(图片有点大,不知道会不会不清晰,如果不清晰可以按照上面说的idea生成方法去生成即可)
:
可以看到Resource
是整个体系的根接口,点进源码可以看到它定义了许多的策略方法
,因为它是用了策略模式
这种设计模式,运用的好处就是策略接口/类
定义了同一的策略,不同的子类有不同的具体策略实现,客户端调用时传入一个具体的实现对象比如UrlResource或者FileSystemResource
给策略接口/类Resource
即可!
所有策略
如下:
-
2、上面讲了 Spring 框架对各种资源的抽象采用了
策略模式
,那么问题来了,现在表示资源的东西有了,那么是怎么把该资源加载进来呢?于是就有了下面的ResourceLoader
组件,该组件负责对 Spring 资源的加载,资源指的是xml
、properties
等文件资源,返回一个对应类型的Resource
对象。。UML 图如下:
从上面的 UML 图可以看出,ResourceLoader
组件其实跟Resource
组件差不多,都是一个根接口,对应有不同的子类实现,比如加载来自文件系统的资源,则可以使用FileSystemResourceLoader
, 加载来自ServletContext
上下文的资源,则可以使用ServletContextResourceLoader
。还有最重要的一点,从上图看出,ApplicationContext
,AbstractApplication
是实现了ResourceLoader
的,这说明什么呢?说明我们的应用上下文ApplicationContext
拥有加载资源的能力,这也说明了为什么可以通过传入一个String resource path
给ClassPathXmlApplicationContext("applicationContext.xml")
就能获得 xml 文件资源的原因了!清晰了吗?nice!
-
3、上面两点讲到了,好!既然我们拥有了加载器
ResourceLoader
,也拥有了对资源的描述Resource
, 但是我们在 xml 文件中声明的<bean/>
标签在 Spring 又是怎么表示的呢?注意这里只是说对bean
的定义,而不是说如何将<bean/>
转换为bean
对象。我想应该不难理解吧!就像你想表示一个学生Student
,那么你在程序中肯定要声明一个类Student
吧!至于学生数据是从excel
导入,或者程序运行时new
出来,或者从xml
中加载进来这些都不重要,重要的是你要有一个将现实中的实体表示为程序中的对象的东西,所以<bean/>
也需要在 Spring 中做一个定义!于是就引入一个叫BeanDefinition
的组件,UML 图如下:
下面讲解下 UML 图:
首先配置文件中的<bean/>
标签跟我们的BeanDefinition
是一一对应的,<bean>
元素标签拥有class
、scope
、lazy-init
等配置属性,BeanDefinition
则提供了相应的beanClass
、scope
、lazyInit
属性。
其中
RootBeanDefinition
是最常用的实现类,它对应一般性的<bean>
元素标签,GenericBeanDefinition
是自2.5
以后新加入的bean
文件配置属性定义类,是一站式服务类。在配置文件中可以定义父<bean>
和子<bean>
,父<bean>
用RootBeanDefinition
表示,而子<bean>
用ChildBeanDefiniton
表示,而没有父<bean>
的<bean>
就使用RootBeanDefinition
表示。AbstractBeanDefinition
对两者共同的类信息进行抽象。Spring
通过BeanDefinition
将配置文件中的<bean>
配置信息转换为容器的内部表示,并将这些BeanDefiniton
注册到BeanDefinitonRegistry
中。Spring
容器的BeanDefinitionRegistry
就像是Spring
配置信息的内存数据库,