自定义Spring框架 · 设计模式
省略 getter 、setter 、构造函数
代码块收起展开
XML / 注解配置
↓
PropertyValue(原始数据)
↓
MutablePropertyValue(处理、合并、修改)
↓
注入 Bean1. PropertyValue
用来存储xml文件的bean相关描述字段, PropertyValue = 一个“不可变”的属性键值对
代码块收起展开
@Data
@Lombok
public class PropertyValue {
private final String name;
private final Object value; //new RuntimeBeanReference(" num / ref / List or Map")
}2. MutablePropertyValues
内置一个 List , 用以管理多个 PropertyValue 对象
代码块收起展开
class MutablePropertyValues {
private List<PropertyValue> propertyValueList;
}再贴回 Spring 场景
代码块收起展开
<bean id="user">
<property name="name" value="Tom"/>
<property name="age" value="18"/>
</bean>在内存里其实是:
代码块收起展开
MutablePropertyValues
├── PropertyValue(name, "Tom")
└── PropertyValue(age, 18)👉 一个 Bean 的“所有属性集合”
返回所有 PropertyValue
- 直接 list.toArray 返回的是object类型
- 因此看看list接口还有无类似方法, 发现第二种方法
代码块收起展开
Object[] toArray();
<T> T[] toArray(T[] var); //返回泛型, 选这种- 点击ArrayList中的具体实现, 补足长度并且类型转换也符合
代码块收起展开
public <T> T[] toArray(T[] a){
if(a.length < this.size){
return (T[]) Arrays.copyOf ( this.elementData, this.size, a.getClass() );
}else {
System.arraycopy(this.elementData, i, a, 0, this.size); //o, i, o1, i1, i2
if(a.length > this.size){
a[this.size]=null;
}
return a;
}
} 禁止直接强制类型转换(PropertyValue[]), 会出现ClassCastException异常
3. BeanDefinition
记录<bean>标签的内容
include
包含 id、className、propertyValues(dependency bean) 因此内置一个MutablePropertyValues来管理propertyValues
代码块收起展开
class BeanDefinition {
private String beanName;
private String beanClassName;
private String scope;
private MutablePropertyValues propertyValues;
}4. BeanDefinitionRegistry
管理Bean
- 提供增删改查 Bean对象
- 为了查找方便, 内置一个HashMap <String, BeanDefinition>
5. BeanDefinitionReader
解析配置文件
- 获得
registry注册表 - 通过配置文件路径获取
BeanDefinition并注册Bean
6. xmlBDReader子实现类
Reader接口 只提供大概方法, 具体是啥配置文件、有不同的解析工具和方法, 这里是其中一种 xml 配置
Dom4j Java-base 用以操作 xml 配置文件,可以让我们读取、修改 xml 文件的内容。
内置一个注册表 构造的时候直接传递一个 SimpleBDRegistry,并且提供 getRegistry()。
加载 BeanDefinitions 进 registry
-
形参为 ConfigPath,然后通过本类的类加载器获取输入流,用 SAXReader 读取。
-
获取根标签<beans>,并且得到所有<bean> 标签。
-
for 循环处理每个<bean> 的内容: id、className、properties(name, ref, value)。
-
create BeanDefinition,然后封装处理后的内容,并且写入注册表中。
7. BeanFactory & ApplicationContext接口
BeanFactory接口
bean 工厂,提供 getBean 方法。
ApplicationContext子接口
BeanFactory 的子接口,多一个 efresh 方法。
AbstractApplicationContext
子实现类
- 内置类路径
- 配置文件解析器
- 存 bean 实例的 singletonMap
refresh
- 调用解析器的 loadBeanDefinition。
- 调用 finishBeanInitialization():获取注册表,并且遍历 getBeanByName。
ClassPathXmlApplicationContext子类
- 在构造函数调用
efresh 进行 bean 的实例化。
- 读取 xml 文件,并且添加所有 bean 进注册表。
- finishBeanDefinitionIntialization 通过 for 循环 getBean 预热所有 bean。
- 注意:这里的 getBean 方法会将实例化后的 bean 存放进 singletonMap,所以下次调用时就可以直接返回。
- 重写 getBean 方法。
- 查找 singletonMap 是否已有该 Bean,有则返回。
- 没有则通过 BeanDefinitionRegistry 找到对应 BeanDefinition。
- BeanDefinition 中保存了 ame,因此通过反射 ewInstance。
- 最重要的是进行依赖注入:properties。
图片未随原笔记同步:image04|650
- 如果 singletonMap 中还没有该 bean,就放进去,供后续直接复用。
- 注意这个方法是 getBean,最终一定要返回 Bean。