SpringIOC的初步理解
前言:这是在慕课网上学习剑指Java面试-Offer直通车时所做的笔记
目录
第一章 IOC原理
IOC(Inversion of control) :控制反转
IOC可以说是Spring最核心的部分,是Spring家族任意组件的基本,IOC本身并不能算为一种技术而是一种思想,它使你从繁琐的对象交互中解脱出来,进而专注于对象本身,更进一步突出面向对象,要了解控制反转,要先了解一个软件设计的重要思想即依赖注入.
举例:
设计行李箱
不用依赖注入:
本身的代码:上层建筑依赖下层建筑
现在我们要修改*的大小
用依赖注入:
修改*的大小:
这种设计模式还有利于协同合作和单元测试.
比如上述四个模块是由四个小队开发的,只要定义好了接口,四个小队可以同时开发而不相互受到限制.
测试Luggage时只要mock Framework类传入Luggae就行了.不用把其余三个类全部new一遍了.
上述这种以DI实现的IOC给我们带了很大的编译,其实DI还有DL的实现方式,会在需要的时候调用框架提供的方法来获取Bean,现在DL已经被抛弃了.DI是当今IOC的主流实现.
依赖注入的方式:
Setter: 实现特定属性的public Setter方法,来让IOC容器调用注入所依赖类型的对象.
Interface: 实现特定的接口以供IOC容器注入所依赖类型的对象.
Constructor: 实现特定参数的构造函数,在创建对象时来让IOC注入所依赖的对象.
Annotation: 通过Java的注解机制,来让IOC容器注入所依赖类型的对象.(Autowired)
依赖导倒置原则,IOC,DI,IOC容器之间的关系
依赖倒置原则是一种思想,高层模块不应该依赖于底层模块.两者都应依赖其抽象.正是依赖倒置原则的指导,才有了IOC的思路,实现IOC离不开DI,Spring框架基于IOC才提出了容器的概念,对于IOC来说最重要的就是容器.容器管理着Bean的声明周期和容器的依赖注入.
那什么是IOC Container呢?
下面的代码就是IOC容器所做的事情了.
容器可以自动对代码进行初始化,开发者只需维护一个Configuration.
IOC要求我们的class要有配置文件,这样我们实例化对象时不用一个一个的去看构造函数,IOC会自动根据配置进行创建.
第二章 SpringIOC的应用
Spring启动时去读取应用程序提供的Bean配置信息,并在Spring容器中生成相应的Bean定义注册表,然后根据注册表去实例化Bean,装配好Bean之间的依赖关系,为上层提供准备就绪的运行环境.
Spring提供一个配置文件描述Bean与Bean之间的依赖关系,利用Java语言的反射功能实例化Bean,并建立Bean之间的依赖关系.
SpringIOC容器的核心接口
2.1 BeanFactory
核心接口:
BeanDefinition:主要用来描述Bean的定义,Spring在启动时会将Xml或者注解里Bean的定义解析成Spring内部的BeanDefinition.
BeanDefinitionRegistry:提供向IOC容器注册BeanDefinition对象的方法.
举例:新建SpringBoot的项目
registerBeanDefinition方法主要是将BeanDefinition注册到BeanFactory接口的实现类DefaultListableBeanFacory中的beanDefinitionMap中,Spring将Bean的定义解析成Definition之后会通过DefinitionRegistry以BeanName为key,BeanDefinition为value存储到BeanDefinitionMap里面,同时将BeanName存储到beanDfinitionNames里,以便后序Bean的实例化.
BeanFactory是Spring框架最核心的接口,能将Bean从客户端的配置中解放出来,其的主要作用为:
提供了IOC的配置机制
BeanFactory包含Bean的各种定义,以便实例化Bean.
在实例化时建立Bean之间的依赖关系.
Bean生命周期的控制.
其的主要的结构图为:
ListableBeanFactory该接口定义了访问容器中Bean的若干方法,如查看Bean的个数,获取某一类型Bean的配置名,查看容器中是否包括某一Bean等方法.
HierarchicalBeanFactory是父子级联的IOC容器接口,子容器可以通过接口方法访问父容器,通过HierarchicalBeanFactory接口SpringIOC可以建立父子层级关联的IOC层级体系,子容器可以访问父容器的Bean,父容器不能访问子容器的Bean,比如展现层的Bean位于子容器中而业务层和持久层的Bean位于父容器的Bean.
ConfigurableBeanFactory:增强了IOC接口的可定制性,定义了设置类装载器,属性遍历器,以及属性初始化后置处理器等方法.
AutowireCapableBeanFactory:定义了将容器中的Bean按某种规则,按名字匹配,按类型匹配等.
SingletonBeanRegistry:允许在运行期间向容器注册SingletonBean实例的方法.
通过这些接口也证明了BeanFactory的体系也确实提供了IOC的基础及依赖注入和Bean的装载等功能.
代码实例:
打开BeanFactory可以看到多个getBean方法, 这也是Spring容器最重要的方法之一, 从Spring容器中获取Bean,可以按类型名称获取Bean,isSingleton判断Bean是否是单例,.
2.2 ApplicationContext
由于BeanFactory的功能还不够强大,于是Spring在BeanFactory的基础上还设计了一个更为高级的接口即ApplicationContext,它是BeanFactory的子接口之一.在我们使用SpringIOC容器时,大部分都是context的实现类.
终极结构图:
代码实例:
点进run方法中,层层递进,逢run就点
点到有很多代码的地方,往下翻就会找到如下,发现会根据类型去加载AplicationContext,会通过Class.forname去加载...WebServerAppliacationContext
第三章 SpringIOC的refresh源码解析
首先和之前一样,点进SpringApplication的run方法中,层层往下点,直到点到如下为止
将代码拖动到如下位置,createApplicationContext我们刚才讲过是依据不同的配置加载不同的ApplicationContext
再往下最核心的是refreshContext方法,点进去可以看到如下,前端是refresh,调用了AbstractApplicationContext中的refresh方法,
prepareRefresh:完成配置之类的解析,设置Spring的状态,初始化属性源信息,验证环境信息中必须存在的属性.
ConfigurableListableBeanFactory是用来获取beanFactory的实例的.
prepareBeanFactory:对beanFactory进行相关的设置,为后续的使用做准备,包括设置classLoader用来加载Bean,设置表达式解析器等等.
postProcessBeanFactory:是用于在BeanFactory设置之后进行后续的BeanFactory的操作.
invokeBeanFactoryPostProcessors:点进去发现调用了如下方法,点进去之后发现逻辑相当复杂,主要调用工厂后处理器,调用Bean标签,扫描Bean文件,并解析成一个个的Bean,这时候这些Bean是被加载进了Spirng容器当中
,这里涉及了各种类,我们在这里主要讲解一下ConfigurationClassParser.主要是解析Bean的类.该方法会对带有@configuration,@import,@bean,以及@SpringBootApplication等标签的Bean进行解析,
registerBeanPostProcessors:会从Spring容器中找出实现BeanPostProcessors接口的Bean,并设置到BeanFactory的属性之中,之后Bean实例化时会调用BeanProcessor,也就是Bean的后置处理器.会和AOP比较相关.
initMessageSource:初始化国
initApplicationEventMuticaster:初始化事件广播器
onRefresh:是一个模板方法,不同的Spring容器会重写它做不同的事情.比如web程序的容器,会调用create..方法去创建内置的servlet容器.
registerListeners:注册事件监听器
finishBeanFactoryInitialization:会实例化BeanFactory中已被注册但未被实例化的所有实例,懒加载是不需要被实例化的.前面的invokeBeanFactoryPostProcessors方法中根据各种注解解析出来的Bean在这个时候都会被初始化,同时初始化过程中的各种PostProcessor就会开始起作用了.
finishRefresh:会做初始化生命周期处理器相关的事情.
后面是注册钩子,这钩子是希望开发者能结合自己的实际需求扩展出一些在Spring容器关闭时的行为.
再往下我们可以看到afterRefresh方法,它的方法体是空的, 也就说明Spring框架考虑了扩展性,留了很多的口子,让大家在框架层面继承很多的模块并去做自定义的实现.
第四章 SpringIOC的getBean方法的解析
getBean方法用来加载Bean,我们发现所有的getBean都最终会调用doGetBean方法,点击进去
我们打上断点运行项目,发现确实会调用doGetBean来实例化Bean,首先通过transformedBeanName提取出BeanName的名字,获取到BeanName后会根据singleton方法获取一个共享的实例,这个实例可能是Bean的实例也有可能是一些工厂的实例,获取到这些实例后就会调用getObjectForBeanInstance方法,去试着从缓存或者实例工厂中去获取实例,如果getSingleton获取不到的话,它就会尝试从parentBeanFactory中去获取.
然后会将父类的属性与子类的属性进行合并.注意dependsOn不等于空,如果存在依赖,就要递归去实例化依赖存在的Bean,
判断Bean的作用域是否是singleton,如果是就看先前是否创建过,如果有的话直接返回,如果没有就创建一个,如果作用于是protype,就new一个出来,如果是其它范围会按照else的范围创建.
第五章 小的知识点
5.1 SpringBean的作用域
5.2 创建过程
实例化bean和其属性,容器管理的Bean一般不需要了解容器,这时就需要设置对容器的感知,可以通过Aware接口完成.紧接着调用BeanPostProcessor前置初始化方法,在Spring完成实例化之后对Spring实例化后的Bean添加一些自定义的处理逻辑,然后经过一些过程,再调用BeanPostProcessor的后置初始化方法.去做一些Bean实例初始化后的自定义工作与AOP相关
5.3 销毁过程