源码解析-SpringIOC容器

盲人摸象盲人摸象

这一篇可能并没有涉及到太多源码层细节实现,而是为了能更好的从概念上理解Spring IOC容器这个框架

 

前言:

对Spring这个框架稍有熟悉就会了解到

Spring这个框架的功能是啥?   答: IOC+DI 与 AOP

IOC+DI是啥意思?    答:控制反转 +  依赖注入 

说人话?    

答: 控制反转是思想层的 依赖注入是具体实现。他俩说的是一回事。 啥事呢 说白了就是为了让对象之间实现解耦

我们之前对象A需要依赖对象B,需要自己手动new一个对象B 给A使用,需要的时候就new一个 需要的时候就new一个,这样A与B的耦合性很强,B的变化引起A发生改变

IOC的本质就是 造了一个大容器,目的就是管理可能用到的对象。当一个对象A需要对象B的时候 按要求从容器里直接来拿对象B就行了,对象A不用自己new 也不用关心对象B什么时候生成  对象B生成的细节,只管拿去用就行了。

 

这种思想理解了发现也没啥,但是仔细想想确实很了不起

把对象交给容器来管理,那对象的很多细节 包括很多使用都可以交给容器来做了 会降低很多开发成本。

比如 这个对象创建的创建细节 单例的? 什么时候给他属性?可不可以在这个对象生成之前生成之后做些事情? 销毁?

以对象容器管理为起点,再加上Spring AOP动态代理,spring 对web容器的支持,在往后对数据库连接 以及其他框架 其他组件 其他中间件的支持 逐渐形成spring全家桶  几乎成为java程序员的日常开发框架

本章重点在开始的开始 spring怎么做到IOC的。

先简单思考一下,如果要设计一个框架 作为一个容器来管理对象该如何去设计?会遇到哪些问题?

 

spring容器启动后 会从指定配置文件读取类装配信息,组装成 BeanDifinition 存储在一个Map中,key为Bean的名称或别名 value为BeanDifinition

 

 我们以最原始的.xml配置文件的形式注入实例来分析

启动类ApplicationContext 加载配置文件application.xml,

先看一下ApplicationContext的继承关系

最下一层的几个实现

ClassPathXmlApplicationContext  根据类路径的.xml配置加载

FileSystemXmlApplicationContext  根据系统文件的.xml文件加载

AnnotationConfigApplicationContex  根据注解加载

 

首先要了解Spring很重要的一个概念 BeanFactory 也就是容器工厂,也可以说是Spring容器的总接口

生产 bean 的工厂,它负责生产和管理各个 bean 实例。(在spring中 每一个被管理的对象都被称为Bean)

BeanFactory 方法只能获取单个Bean

ListableBeanFactory 可以获取多个Bean

HierachicalBeanFactory 可以在应用中起多个BeanFactory,并将各个BeanFactory设置为父子关系

 

AutowireCapableBeanFactory  根据注解自动装配

ConfigurableListableBeanFactory  继承了第二层三个接口,

DefaultListableBeanFactory  这个画重点,这老哥继承了上边所有的接口,也是最重要的一个类

ApplicationContext 继承了BeanFactory接口,但其实他其实并不是容器的最终实现,不如说他是一个代理,它的内部存的一个BeanFactory才是真正的实现

 

 

源码分析

BeanFactory 

作为一个工厂的根本,他的职能很明显了,对外提供了多种getBean()方法,   获取别名,获取类型,是否单例等

原始工厂就是这样朴实无华且枯燥,更多的功能以及实现的具体细节全都在子类了

 

ApplicationContext 继承自BeanFactory, 以容器的身份出现,职能就是 获取容器id,获取容器名称,获取父容器等 (由于spring可以启动多个容器,还有父子容器等概念 子容器会继承父容器的全部配置)

具有BeanFactory的所有功能,又因为其继承了MessageSource, ApplicationEventPublisher, ResourcePatternResolver接口,因此又具有国际化消息解析,资源加载,ApplicationEvent事件发布的功能。

在此接口自己定义的方法中提供了获取父ApplicationContext、获取自动装配bean工厂,获取启动时间和显示名称这四项功能。

 

我们从new ClassPathXmlApplicationContext("path") 为入口追一下容器的启动过程

参数1 配置文件地址

参数2 是否需要刷新  默认是true,用来判断是否需要刷新容器

参数3 父容器,主要是用来继承父容器的配置,一般我们用不到 默认null

refresh() 会将原来的 ApplicationContext 销毁,然后再重新执行一次初始化操作。

 

 

 

 最重点的两步

ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();  //读取配置文件 然后把所有bean加载进容器,保存成BeanDifinition的Map

finishBeanFactoryInitialization(beanFactory); //初始化所有singleton的Bean

 

 

 

 

 

posted @ 2020-12-08 20:22  六小扛把子  阅读(84)  评论(0编辑  收藏  举报