欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Spring知识梳理

程序员文章站 2022-03-30 13:11:53
...

前言

最近在看Spring的源码,非常头大,因为能力有限不准备对源码进行很深的研究,只是希望在这里将大概原理做一个梳理,以应付面试用,待以后再深入学习Spring的源码吧。

Spring的设计理念

在JAVA EE的开发中,支持使用POJO和JavaBean的开发方式,使应用面向接口开发,充分支持OO(面向对象)的设计方法。(现在还不太能理解这句话的意思,也许需要比较传统的EJB开发模式才能体会出Spring的方便之处)。Spring作为平台的一大优点,就是针对JAVA代码的解耦。他可以允许我们通过一个或者几个XML文件对JAVA中的耦合关系进行预览和相关操作,同时通过IOC容器实现的依赖反转,把依赖关系的管理从JAVA对象中解放出来交给IOC容器(或者说Spring框架)来完成,从而完成了对象之间的解耦,原来的对象-对象的关系变成了对象-IOC容器-对象的关系。

Spring的价值

1.Spring是一个非侵入式的框架。他会尽量将应用程序代码对框架的依赖最小化,使之在没有框架的情况下依旧可以运行。(没有感觉,可能理解不深)。
2.Spring提供了一个一致的编程模型,让应用直接使用POJO开发,从而与运行环境(如服务器)隔离开来。
3.Spring推动设计风格向面向对象面向接口转变。
4.Spring是一个开放式的平台,他允许我们选择其他诸多组件,比如Mybatis。

IOC容器和依赖反转

什么是依赖反转?即创建对象的义务被容器接管,业务逻辑代码中无需再考虑依赖对象的创建,所以也叫依赖注入,将对其他对象的依赖注入到现在对象中。比如以前我们需要在UserService中使用WalletService,需要写如下代码:WalletService walletService = new WalletService(),但当我们需要将WalletService中的构造函数改为有一个String参数时,就需要将每一个上述代码修改为这样WalletService walletService = new WalletService("str"),这无疑增加了我们的工作量,而依赖反转帮助我们解决了这个问题,我们不管对WalletService进行如何更改,IOC容器都会帮助我们将依赖注入到我们操作的对象中。Spring框架最主要的主体就是IOC容器,其他的例如AOP都是他提供的功能,所以有的时候我们称呼Spring框架为IOC容器也并不过分。

IOC容器的初步实现:BeanFactory

我们把IOC容器比作一个水桶,水桶需要有他自己的定义才能被叫为水桶,比如圆柱形上面无盖能装水等等,而BeanFactory就是对水桶最基本的定义规则。其他继承他的接口比如ListableBeanFactory是一些扩展定义规则,比如木制水桶规定需要材质为木头等等。真正的水桶产品是实现这些接口的实现类,比如我们经常用到的DefaultListableBeanFactory,他代表一个实实在在的产品,比如木制水桶,DefaultListableBeanFactory可以看做是一个功能完备的IOC容器实例,可以供我们进行使用,其他IOC容器都是在他的基础上进行的功能扩展,比如XMLBeanFactory等。IOC中的BeanFactory接口体系设计的非常灵活,他基本上将每一个不同的点都设计成接口以便复用和扩展,所以我们最后看到的水桶规则其实是很多细小规则累加之后的产品。下面的一段代码表示IOC容器的启动:

//Spring中的Resource代表着各种资源对象,我们知道Spring需要在例如XML的文件中进行很多配置,Resource就是Spring将这些配置文件封装成的对象
ClassPathResource resource = new ClassPathResource("beanFactoryTest.xml");

//实例化Factory,这里相当于已经启用了一个无用的、空的IOC容器
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();

//我们需要将Resource中的配置信息放到Factory中以供Factory使用,XmlBeanDefinitionReader就是读取Resource中信息的对象
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);

//调用XmlBeanDefinitionReader对象的loadBeanDefinitions方法,将配置信息写入Factory,这时候Factory已经有了我们的相关设置,已经达到了使用的标准
reader.loadBeanDefinitions(resource);

IOC容器的高级实现:ApplicationContext

ApplicationContext也是IOC系统的实现方法,他比BeanFactory更高级,BeanFactory 使用的时候我们还需要进行其他的操作,比如将设置传入BeanFactory等等,但ApplicationContext已经自带了这些功能,就无需我们再关心这些事情。我们以FileSystemXmlApplicationContext为例,在初始化的过程中是调用AbstractApplicationContext类中的refresh()方法来启动整个BeanDifinition的载入过程的,这个初始化是通过XmlBeanDefinitionReader来完成,IOC容器实际上使用的是DefaultListableBeanFactory,具体的Resource载入在XmlBeanDefinitionReader读入BeanDifinition时实现。

IOC容器的初始化过程

  1. Resource的定位过程。这个定位过程其实就是BeanDefinition的资源定位,他由ResourceLoader通过统一的Resource接口来完成。从名称就可以知道他的实现类是做什么用的,比如:ClassPathResource是从根路径中查找配置资源。这个过程就相当于打水的时候先把水找到。关于XML资源类型的资源定位是在XmlBeanDefinitionReader类中的loadBeanDefinitions(EncodedResource encodedResource)方法中进行实现的。感兴趣的自己可以再查找资料好好了解一下。
  2. BeanDifinition的载入和解析。这个载入过程就是将用户定义好的bean表示成IOC容器内的数据结构,他实际上就是POJO对象在IOC容器里的抽象,通过BeanDifinition,IOC可以很方便的对POJO对象也就是Bean进行管理。IOC容器是通过一个HashMap来保持和维护这些BeanDifinition的。如果把IOC容器比作是水桶的话,那BeanDifinition就是水桶里的水。BeanDifinition的载入就相当于我们把水倒入水桶中。这个载入过程也是在XmlBeanDefinitionReader类中的loadBeanDefinitions(EncodedResource encodedResource)方法中进行实现的,如果是ApplicationContext的启动方式,则是在AbstractXmlApplicationContext类中的loadBeanDefinitions(XmlBeanDefinitionReader reader)方法中调用了XmlBeanDefinitionReader类中的loadBeanDefinitions(EncodedResource encodedResource)方法。解析是在DefaultBeanDefinitionDocumentReader类中的processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate)方法中实现。
  3. .BeanDifinition的注册。在BeanDifinition载入IOC容器之后,我们需要将BeanDifinition向IOC容器进行注册,这里你可以这样理解,我们将水装入水桶后需要告诉一下水桶,这样水桶才知道里面已经装了水,这个过程是调用BeanDifinitionRegistry接口的实现来完成的,在IOC内部将BeanDifinition注入到一个HashMap中去。

SpringMVC启动的基本过程

IOC的启动过程就是上下文的启动过程,该上下文是与ServletContext相伴而生的,同时也是IOC容器在WEB应用环境中的具体表现之一。由ContextLoaderListener启动的上下文为根上下文,在根上下文的继承下还有一个与WEB MVC相关的上下文用来保存控制器(DispatcherServlet)需要的MVC对象,作为根上下文的子上下文。