自定义Spring框架 · 设计模式

省略 gettersetter构造函数

代码块TEXT · 7 行收起展开
XML / 注解配置

PropertyValue(原始数据)

MutablePropertyValue(处理、合并、修改)

注入 Bean

1. PropertyValue

用来存储xml文件的bean相关描述字段, PropertyValue = 一个“不可变”的属性键值对

代码块JAVA · 6 行收起展开
@Data
@Lombok
public class PropertyValue {
    private final String name;
    private final Object value; //new RuntimeBeanReference(" num / ref / List or Map")
}

2. MutablePropertyValues

内置一个 List , 用以管理多个 PropertyValue 对象

代码块JAVA · 3 行收起展开
class MutablePropertyValues {
    private List<PropertyValue> propertyValueList;
}

再贴回 Spring 场景

代码块XML · 4 行收起展开
<bean id="user">  
    <property name="name" value="Tom"/>  
    <property name="age" value="18"/>  
</bean>

在内存里其实是:

代码块JAVA · 3 行收起展开
MutablePropertyValues  
    ├── PropertyValue(name, "Tom")  
    └── PropertyValue(age, 18)

👉 一个 Bean 的“所有属性集合”

返回所有 PropertyValue

  1. 直接 list.toArray 返回的是object类型
  2. 因此看看list接口还有无类似方法, 发现第二种方法
代码块JAVA · 2 行收起展开
   Object[] toArray();
   <T>  T[] toArray(T[]  var);   //返回泛型, 选这种
  1. 点击ArrayList中的具体实现, 补足长度并且类型转换也符合
代码块JAVA · 11 行收起展开
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异常

Pasted image 20260417150545

3. BeanDefinition

记录<bean>标签的内容

include

包含 id、className、propertyValues(dependency bean) 因此内置一个MutablePropertyValues来管理propertyValues

代码块JAVA · 7 行收起展开
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

  1. 形参为 ConfigPath,然后通过本类的类加载器获取输入流,用 SAXReader 读取。

  2. 获取根标签<beans>,并且得到所有<bean> 标签。

  3. for 循环处理每个<bean> 的内容: id、className、properties(name, ref, value)。

  4. create BeanDefinition,然后封装处理后的内容,并且写入注册表中。

7. BeanFactory & ApplicationContext接口

BeanFactory接口

bean 工厂,提供 getBean 方法。

ApplicationContext子接口

BeanFactory 的子接口,多一个 efresh 方法。

AbstractApplicationContext

子实现类

  • 内置类路径
  • 配置文件解析器
  • 存 bean 实例的 singletonMap

refresh

  1. 调用解析器的 loadBeanDefinition。
  2. 调用 finishBeanInitialization():获取注册表,并且遍历 getBeanByName。
Pasted image 20260417152057

ClassPathXmlApplicationContext子类

  1. 在构造函数调用 efresh 进行 bean 的实例化。
    • 读取 xml 文件,并且添加所有 bean 进注册表。
    • finishBeanDefinitionIntialization 通过 for 循环 getBean 预热所有 bean。
  2. 注意:这里的 getBean 方法会将实例化后的 bean 存放进 singletonMap,所以下次调用时就可以直接返回。
  3. 重写 getBean 方法。
    • 查找 singletonMap 是否已有该 Bean,有则返回。
    • 没有则通过 BeanDefinitionRegistry 找到对应 BeanDefinition。
Pasted image 20260417152049
  • BeanDefinition 中保存了 ame,因此通过反射 ewInstance。
Pasted image 20260417152041
  • 最重要的是进行依赖注入:properties。

图片未随原笔记同步:image04|650

  1. 如果 singletonMap 中还没有该 bean,就放进去,供后续直接复用。
  2. 注意这个方法是 getBean,最终一定要返回 Bean。