作者:小傅哥
博客:https://bugstack.cn
积淀、分享、成长,让本人和别人都能有所播种!😄
一、前言
上学时,老师总说:不会你就问,但少数时候都不晓得要问什么!
你总会在小傅哥的文章前言里,发现一些对于成长、学习、感悟以及对当篇内容的一个介绍,其实之所以写这样的铺垫性内容,次要是为了让大家对接下来的内容学习有一个较轻松的收场和适度。
就像咱们上学时如果某一科的内容不会时,老师常常会说,你有不会的就要问。但对于学生自身来讲,可能曾经不会的太多了,或者压根不晓得本人不会什么,只有等看到老师出完的试卷才发现自己什么都不会。但要是让问,又不晓得从哪问,问出萝卜带出泥,到处都是常识破绽。
所以我心愿用一些前置内容的铺垫,让大家能够在一个稍有共识的场景下进行学习,或多或少能为你铺垫出一个稍许平缓的承受期。有可能某些时候也会打打鸡血、刺激刺激学习、总归把常识学到手就是好的!
二、指标
Spring Bean 容器是什么?
Spring 蕴含并治理利用对象的配置和生命周期,在这个意义上它是一种用于承载对象的容器,你能够配置你的每个 Bean 对象是如何被创立的,这些 Bean 能够创立一个独自的实例或者每次须要时都生成一个新的实例,以及它们是如何互相关联构建和应用的。
如果一个 Bean 对象交给 Spring 容器治理,那么这个 Bean 对象就应该以相似整机的形式被拆解后寄存到 Bean 的定义中,这样相当于一种把对象解耦的操作,能够由 Spring 更加容易的治理,就像解决循环依赖等操作。
当一个 Bean 对象被定义寄存当前,再由 Spring 对立进行拆卸,这个过程包含 Bean 的初始化、属性填充等,最终咱们就能够残缺的应用一个 Bean 实例化后的对象了。
而咱们本章节的案例指标就是定义一个简略的 Spring 容器,用于定义、寄存和获取 Bean 对象。
三、设计
但凡能够存放数据的具体数据结构实现,都能够称之为容器。例如:ArrayList、LinkedList、HashSet 等,但在 Spring Bean 容器的场景下,咱们须要一种能够用于寄存和名称索引式的数据结构,所以抉择 HashMap 是最合适不过的。
这里简略介绍一下 HashMap,HashMap 是一种基于扰动函数、负载因子、红黑树转换等技术内容,造成的拉链寻址的数据结构,它能让数据更加散列的散布在哈希桶以及碰撞时造成的链表和红黑树上。它的数据结构会尽可能最大限度的让整个数据读取的复杂度在 O(1) ~ O(Logn) ~O(n)之间,当然在极其状况下也会有 O(n) 链表查找数据较多的状况。不过咱们通过 10 万数据的扰动函数再寻址验证测试,数据会平均的散列在各个哈希桶索引上,所以 HashMap 非常适合用在 Spring Bean 的容器实现上。
另外一个简略的 Spring Bean 容器实现,还需 Bean 的定义、注册、获取三个根本步骤,简化设计如下;
- 定义:BeanDefinition,可能这是你在查阅 Spring 源码时常常看到的一个类,例如它会包含 singleton、prototype、BeanClassName 等。但目前咱们初步实现会更加简略的解决,只定义一个 Object 类型用于寄存对象。
- 注册:这个过程就相当于咱们把数据寄存到 HashMap 中,只不过当初 HashMap 寄存的是定义了的 Bean 的对象信息。
- 获取:最初就是获取对象,Bean 的名字就是 key,Spring 容器初始化好 Bean 当前,就能够间接获取了。
接下来咱们就依照这个设计,做一个简略的 Spring Bean 容器代码实现。编码的过程往往并不会有多简单,但通晓设计过程却更加重要!
四、实现
1. 工程构造
small-spring-step-01
└── src
├── main
│ └── java
│ └── cn.bugstack.springframework
│ ├── BeanDefinition.java
│ └── BeanFactory.java
└── test
└── java
└── cn.bugstack.springframework.test
├── bean
│ └── UserService.java
└── ApiTest.java
工程源码:https://github.com/small-spring/small-spring-step-01
Spring Bean 容器类关系,如图 2-2
Spring Bean 容器的整个实现内容非常简单,也仅仅是包含了一个简略的 BeanFactory 和 BeanDefinition,这里的类名称是与 Spring 源码中统一,只不过当初的类实现会相对来说更简化一些,在后续的实现过程中再一直的增加内容。
- BeanDefinition,用于定义 Bean 实例化信息,当初的实现是以一个 Object 寄存对象
- BeanFactory,代表了 Bean 对象的工厂,能够寄存 Bean 定义到 Map 中以及获取。
2. Bean 定义
cn.bugstack.springframework.BeanDefinition
public class BeanDefinition {
private Object bean;
public BeanDefinition(Object bean) {this.bean = bean;}
public Object getBean() {return bean;}
}
- 目前的 Bean 定义中,只有一个 Object 用于寄存 Bean 对象。如果感兴趣能够参考 Spring 源码中这个类的信息,名称都是一样的。
- 不过在前面陆续的实现中会逐步完善 BeanDefinition 相干属性的填充,例如:SCOPE_SINGLETON、SCOPE_PROTOTYPE、ROLE_APPLICATION、ROLE_SUPPORT、ROLE_INFRASTRUCTURE 以及 Bean Class 信息。
3. Bean 工厂
cn.bugstack.springframework.BeanFactory
public class BeanFactory {private Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>();
public Object getBean(String name) {return beanDefinitionMap.get(name).getBean();}
public void registerBeanDefinition(String name, BeanDefinition beanDefinition) {beanDefinitionMap.put(name, beanDefinition);
}
}
- 在 Bean 工厂的实现中,包含了 Bean 的注册,这里注册的是 Bean 的定义信息。同时在这个类中还包含了获取 Bean 的操作。
- 目前的 BeanFactory 依然是十分简化的实现,但这种简化的实现内容也是整个 Spring 容器中对于 Bean 应用的最终体现后果,只不过实现过程只展现出根本的外围原理。在后续的补充实现中,这个会一直变得宏大。
五、测试
1. 当时筹备
cn.bugstack.springframework.test.bean.UserService
public class UserService {public void queryUserInfo(){System.out.println("查问用户信息");
}
}
- 这里简略定义了一个 UserService 对象,不便咱们后续对 Spring 容器测试。
2. 测试用例
cn.bugstack.springframework.test.ApiTest
@Test
public void test_BeanFactory(){
// 1. 初始化 BeanFactory
BeanFactory beanFactory = new BeanFactory();
// 2. 注册 bean
BeanDefinition beanDefinition = new BeanDefinition(new UserService());
beanFactory.registerBeanDefinition("userService", beanDefinition);
// 3. 获取 bean
UserService userService = (UserService) beanFactory.getBean("userService");
userService.queryUserInfo();}
- 在单测中次要包含初始化 Bean 工厂、注册 Bean、获取 Bean,三个步骤,应用成果上贴近与 Spring,但显得会更简化。
- 在 Bean 的注册中,这里是间接把 UserService 实例化后作为入参传递给 BeanDefinition 的,在后续的陆续实现中,咱们会把这部分内容放入 Bean 工厂中实现。
3. 测试后果
查问用户信息
Process finished with exit code 0
- 通过测试后果能够看到,目前的 Spring Bean 容器案例,曾经稍有雏形。
六、总结
- 整篇对于 Spring Bean 容器的一个雏形就曾经实现实现了,相对来说这部分代码并不会难住任何人,只有你稍加尝试就能够承受这部分内容的实现。
- 但对于一个常识的学习来说,写代码只是最初的步骤,往往整个思路、设计、计划,才更重要,只有你晓得了因为什么、所以什么,能力让你有一个真正的了解。
- 下一章节会在此工程根底上扩容实现,要比当初的类多一些。不过每一篇的实现上,我都会以一个需要视角进行指标剖析和方案设计,让大家在学习编码之外更能重视更多技术价值的学习。
七、系列举荐
- 毕业前写了 20 万行代码,让我从成为同学眼里的面霸!
- HashMap 外围常识,扰动函数、负载因子、扩容链表拆分,深度学习
- HashMap 数据插入、查找、删除、遍历,源码剖析
- 看图谈话,解说 2 - 3 均衡树「红黑树的前身」
- 《SpringBoot 中间件设计和开发》| 对,小傅哥这次教你造火箭!