最近学习极客时间上的课程,记录一下。
实现Spring IoC
1 原始IoC
首先是Bean Factory,存在的意义是将创建对象与实用对象的业务代码解耦,让业务开发人员无需关注底层对象(Bean)的构建和生命周期管理,专注于业务开发。
第一步,原始 IoC 容器:
-
BeanDefinition → bean在内存中的映像
-
读取XML,获取Bean配置
-
反射,创建Bean
-
Map 保存Bean,并提供给外部使用
相关类
-
BeanDefinition:对应Bean的定义,具有id和className
-
ClassPathXmlApplicationContext:解析某个路径下的 XML 来构建应用上下文
-
readXml 方法,来获取 XML 内的信息
-
instanceBeans 方法,实力化Bean,并放到Map中构建ID与实际类的映射关系。
-
⚠️此时的Context 兼具了 BeanFactory 的功能
第二步,解耦ClassPathXmlApplicationContext
根据设计模式
单一职责原则【SINGLE RESPONSIBILITY PRINCIPLE】: 一个类负责一项职责。
所以要对Context进行功能拆分,在此之前首先梳理Context主要功能。
ClassPathXmlApplicationContext主要功能:
-
一是提出一个最基础的核心容器
-
二是把 XML 这些外部配置信息的访问单独剥离出去,便于其他数据源的扩展。
相关类:
-
BeanFactory接口
-
getBean:获取一个Bean。 实例化Bean,并放到Map中构建映射关系。
-
registerBeanDefinition:注册一个 BeanDefinition。管理其生命周期。
-
-
SimpleBeanFactory:简单实现类
-
Resource接口
-
把外部的配置信息都当成 Resource(资源)来进行抽象。
-
-
ClassPathXmlResource
-
读取的都是 XML 文件配置,另外也可以指定其他数据源
-
-
XmlBeanDefinitionReader
-
将解析好的 XML 转换成 BeanDefinition,并注册到 BeanFactory 中。
-
此时的ClassPathXmlApplicationContext:内部功能以及对应实现类
-
解析 XML 文件中的内容。-- ClassPathXmlResource
-
加载解析的内容,构建 BeanDefinition。-- XmlBeanDefinitionReader
-
读取 BeanDefinition 的配置信息,实例化 Bean,然后把它注入到 BeanFactory 容器中。-- SimpleBeanFactory
2 扩展Bean
上一步实现了原始的IoC容器,下面继续扩展增强 IoC 容器
主要扩展功能如下:
-
增加单例 Bean 的接口定义,然后把所有的 Bean 默认为单例模式。
-
预留事件监听的接口,方便后续进一步解耦代码逻辑。
-
扩展 BeanDefinition,添加一些属性,现在它只有 id 和 class 两个属性,需要进一步完善。
构建单例Bean
首先通过扩展SimpleBeanFactory
来实现单例创建管理
扩展前 VS 扩展后
SimpleBeanFactory 实现了 BeanDefinitionRegistry,这样 SimpleBeanFactory 既是一个工厂同时也是一个仓库
BeanFactory和SingletonBeanRegistry这两个接口,角色分离。一个是工厂,另一个是仓库。
![](https://img-blog.csdnimg.cn/direct/0868d0b26fff495996f30e44709aef35.png)
![](https://img-blog.csdnimg.cn/direct/3be1959074104c8d8807d15f1e94c3bd.png)
下面是Java类的UML关系图,最明显的是属性字段的变更
SimpleBeanFactory之前拥有beanDefinitions, singletons,beanNames三个字段
后面进行拆分
DefaultSingletonBeanRegistry: singletons,beanNames
SimpleBeanFactory: beanDefinitionNames, beanDefinitionMap
扩展前
扩展后
增加事件监听
-
ApplicationEvent :用于监听应用的事件
-
ApplicationEventPublisher:发布事件
注入
注入操作的本质,就是给 Bean 的各个属性进行赋值
-
Setter 注入
-
ArgumentValue
-
ArgumentValues
-
-
构造器注入
-
PropertyValue
-
PropertyValues
-
扩展 BeanDefinition
扩展 BeanDefinition 的属性,在原有 id 与 name 两个属性的基础上,
新增 lazyInit、dependsOn、initMethodName 等属性。
![](https://img-blog.csdnimg.cn/direct/863bb15cbe1f4ae5bb4121d52654d10c.png)
![](https://img-blog.csdnimg.cn/direct/329f4829cb564ebc8607191f711b5008.png)
集中存放 BeanDefinition
新增 BeanDefinitionRegistry 接口。它类似于一个存放 BeanDefinition 的仓库,可以存放、移除、获取及判断 BeanDefinition 对象
调整 BeanFactory,新增 Singleton、Prototype 的判断,获取 Bean 的类型。
3 依赖注入
给Bean注入值并解决循环依赖问题
这一章节要解决的核心是循环依赖问题
Mini-Spring执行步骤:
-
文中先读取配置文件并创建所有的BeanDefinition
-
然后创建毛坯bean放入earlySingletonObjects
-
最后调用refresh方法,对所有的BeanDefinition执行getBean
-
在getBean中进行组装注入依赖,并且注册进入singletonObjects
三级缓存:(Mini-Spring相当于两级缓存)
-
毛胚bean
-
earlySingletonObjects:用于存储早期创建但未完成初始化的单例bean实例。即毛坯
-
-
补齐属性。所有的毛胚bean都是提前创建出来的,后面面对循环依赖的时候,拿到的是这个提前准备好的毛胚bean。
-
singletonObjects:用于存储完全创建好的单例bean实例。
-
-
在Spring里面是一个factory产生的,文中是直接创建的。
-
singletonFactories:用于存储创建单例bean实例的工厂对象。(Spring中)
-
核心代码:
public Object getBean(String beanName) throws BeansException{
// 从singletonObjects中查找bean
Object singleton = this.getSingleton(beanName);
if (singleton == null) {
//从earlySingletonObject中查找bean
singleton = this.earlySingletonObjects.get(beanName);
if (singleton == null) {
BeanDefinition bd = beanDefinitionMap.get(beanName);
//组装创建bean
singleton = createBean(bd);
//注册进singletonObjects
this.registerBean(beanName, singleton);
}
}
return singleton;
}
4 IOC支持注解
这里调试时候发现了一个问题:
注入是通过属性名去查找对应的bean的,即下面的bbs
@AutoWired
private BaseBaseService bbs;
而查找bean毛坯是在earlySingletonObjects,其中的bean名称(basebaseservice)是从xml配置中读取来的
<bean id="basebaseservice" class="com.minis.test.BaseBaseService" init-method="init"></bean>
两者不一致则会导致查找不到对应的bean,从而无法注入注解属性。
将两者调整一致则程序可以正常运行。
注解支持
通过AutowiredAnnotationBeanPostProcessor进行解析属性名,并进行注入
这里需要明确的是,这一步是在所有毛坯bean生成之后进行的步骤,下面在getBean方法中会有解析。
public class AutowiredAnnotationBeanPostProcessor implements BeanPostProcessor {
private AutowireCapableBeanFactory beanFactory;
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
Object result = bean;
Class<?> clazz = bean.getClass();
Field[] fields = clazz.getDeclaredFields();
if(fields!=null){
//对每一个属性进行判断,如果带有@Autowired注解则进行处理
for(Field field : fields){
boolean isAutowired = field.isAnnotationPresent(Autowired.class);
if(isAutowired){
//根据属性名查找同名的bean
String fieldName = field.getName();
Object autowiredObj = this.getBeanFactory().getBean(fieldName);
//设置属性值,完成注入
try {
field.setAccessible(true);
field.set(bean, autowiredObj);
System.out.println("autowire " + fieldName + " for bean " + beanName);
} }}}
return result;}}
public Object getBean(String beanName) throws BeansException{
// 先尝试直接从容器中获取bean实例,从singletonObjects中获取
Object singleton = this.getSingleton(beanName);
if (singleton == null) {
//如果没有实例,则尝试从毛胚实例中获取
singleton = this.earlySingletonObjects.get(beanName);
if (singleton == null) {
//如果连毛胚都没有,则创建bean实例并注册
System.out.println("get bean null -------------- " + beanName);
BeanDefinition bd = beanDefinitionMap.get(beanName);
singleton=createBean(bd);
this.registerBean(beanName, singleton);
//进行beanpostprocessor处理
//step 1 : postProcessBeforeInitialization
applyBeanPostProcessorsBeforeInitialization(singleton, beanName);
//step 2 : init-method
if (bd.getInitMethodName() != null && !bd.getInitMethodName().equals("")) {
invokeInitMethod(bd, singleton);
}
//step 3 : postProcessAfterInitialization
applyBeanPostProcessorsAfterInitialization(singleton, beanName);
}
}
if (singleton == null) {
throw new BeansException("bean is null.");
}
return singleton;
}
新的BeanFactory
这里舍弃了原始的SimpleBeanFactory,使用AbstractBeanFactory 代替,同时用AutowireCapableBeanFactory实现,并扩展了注解处理能力
抽象接口类模式
提取BeanFactory 接口,定义一个抽象的 AbstractBeanFactory。通过这个抽象类,将 Bean 工厂需要做的事情的框架搭建出来,然后在具体实现类中完善细节。这种程序结构称为 interface-abstract-class(接口抽象类),是一种做框架时常用的设计模式。
类关系图如下:
![](https://img-blog.csdnimg.cn/direct/3b523f6cce6e4d07beaeac08b79a4da4.png)
![](https://img-blog.csdnimg.cn/direct/706cd05f55604f64866c12b1e6dc5a9d.png)
执行流程
-
启动 ClassPathXmlApplicationContext 容器,执行 refresh()。
-
在 refresh 执行过程中,调用 registerBeanPostProcessors(),往 BeanFactory 里注册 Bean 处理器,如 AutowiredAnnotationBeanPostProcessor。
-
执行 onRefresh(), 执行 AbstractBeanFactory 的 refresh() 方法。
-
AbstractBeanFactory 的 refresh() 获取所有 Bean 的定义,执行 getBean() 创建 Bean 实例。
-
getBean() 创建完 Bean 实例后,调用 Bean 处理器并初始化。
5 构建工厂体系
接口隔离原则
在 Java 语言的设计中,一个 Interface 代表的是一种特性或者能力,我们把这些特性或能力一个个抽取出来,各自独立互不干扰。如果一个具体的类,想具备某些特性或者能力,就去实现这些 interface,随意组合。这是一种良好的设计原则,叫 interface segregation(接口隔离原则)
IoC 引擎
这一章节对于功能的添加并不多,更多的是类和接口的拆解,下面是拆解前后的结构图
拆解前
拆解后
其中:
-
ConfigurableBeanFactory: 维护 Bean 之间的依赖关系以及支持 Bean 处理器
-
ListableBeanFactory: 对BeanDefinition的管理
-
ConfigurableListableBeanFactory: 集成AutowireCapableBeanFactory、ListableBeanFactory 和 ConfigurableBeanFactory
-
AutowireCapableBeanFactory:由于 ConfigurableListableBeanFactory 继承了 AutowireCapableBeanFactory,
-
所以调整之前定义由 class 改为 interface。
-
-
AbstractAutowireCapableBeanFactory:新增抽象类,替代原有的实现类。
-
DefaultListableBeanFactory:IoC 引擎,它继承了其他 BeanFactory 类来实现 Bean 的创建管理功能
下面是Spring中的继承体图,方便和Mini-Spring对比学习。
事件的发布与监听
-
抽取 ApplicationContext 接口,实现更多有关上下文的内容。
-
支持事件的发布与监听。
-
新增 AbstractApplicationContext,规范刷新上下文 refresh 方法的步骤规范,且将每一步骤进行抽象,提供默认实现类,同时支持自定义。
-
完成刷新之后发布事件。
之前:
之后:
最后让ClassPathXmlApplicationContext继承AbstractApplicationContext,使其集成容器应用上下文和事件发布与监听
public void refresh() throws BeansException, IllegalStateException {
//处理 Bean 以及对 Bean 的状态一些操作
postProcessBeanFactory(getBeanFactory());
registerBeanPostProcessors(getBeanFactory());
//初始化事件发布者
initApplicationEventPublisher();
//初始化完毕的 Bean 进行应用上下文刷新
onRefresh();
//注册监听者
registerListeners();
//完成刷新后进行自定义操作
finishRefresh();
}