spring源码编码哲学

2022/06/30 springboot专题 共 3518 字,约 11 分钟
闷骚的程序员

1. 迭代器模式

Spring 框架的源码设计中,确实广泛应用了迭代器模式(Iterator)、do-while 循环以及复杂的逻辑控制结构。这种设计思路背后的哲学主要体现在以下几个方面:

1.1. 抽象与灵活性

Spring 框架在设计时高度注重抽象层次,允许开发者可以在不同场景下灵活扩展、定制行为。Iteratordo-while 等循环控制结构,能够在保持整体逻辑简洁的前提下,处理不同的实现细节。
比如,do-while 循环通常用于某些框架内部的初始化或任务分配操作,以确保逻辑至少执行一次,并且能够通过条件控制执行多次,方便在不同场景中扩展和复用。

Spring 在处理多个实现类时,通常不会直接硬编码具体实现,而是通过 Iterator 等迭代结构进行动态处理,增强了对集合类的支持。这种方式让框架可以在不修改核心逻辑的情况下,添加、删除或替换不同的实现类,提升了框架的扩展性。

1.2. 责任链模式和递归式处理

责任链模式(Chain of Responsibility)是 Spring 框架中常用的设计模式。比如,处理 BeanPostProcessorHandlerMapping 等结构时,Spring 使用了责任链模式来依次处理每个组件。Iteratordo-while 循环在这种场景下是非常有效的实现方式,可以让框架依次调用不同的组件,直到满足特定条件为止。

在这些设计中,责任链的组件可能是多层次的递归式处理。do-while 或嵌套的循环结构能很好地支持这种逐层调用的逻辑。每一层的处理可能会根据条件返回控制权或继续递归处理下去。

1.3. 容错与延迟加载

Spring 在一些内部机制中使用 do-while 和迭代器的地方往往考虑到了容错处理或延迟加载。do-while 提供了更为灵活的循环控制,避免了直接退出的风险,并确保了至少执行一次的特性,这对于容错和延迟初始化特别有用。例如,在初始化 BeanFactory 时,Spring 需要逐个遍历每个 Bean,在过程中可能会遇到尚未加载的依赖,do-while 循环可以动态调整加载顺序,保证系统的健壮性。

1.4. 模块化与高内聚低耦合

Spring 追求高内聚和低耦合。为了实现这一点,Spring 框架将各种逻辑分解为多个职责单一的模块,这些模块之间通过较为松散的接口或事件系统进行通信。使用 Iterator 等模式,Spring 能够在框架的不同层级之间传递对象、处理逻辑而不显得混乱。
这种设计哲学强调解耦,比如对于 ApplicationContext 的启动过程,Spring 使用了复杂的迭代和循环结构,通过逐层解耦、逐层初始化各个模块,从而确保在框架启动时不同组件的正确顺序与依赖关系得到满足。

1.5. 优雅和高效的资源管理

Spring 在处理资源(如数据源、连接池、事务管理等)时,常通过 Iterator 或循环结构来确保资源被正确地打开和关闭,避免资源泄漏问题。多个资源管理器可能需要按照不同的顺序进行管理,在这种情况下,Spring 会使用 do-while 或其他循环结构来处理每个资源的生命周期,确保每一步操作都得到执行。

1.6. 总结

Spring 源码中的设计追求 抽象性、灵活性、可扩展性和高效性,这些特点通过 Iteratordo-while 等循环结构得到了很好的体现。这些结构可以让框架保持高度的模块化,同时提供强大的扩展能力,确保各个组件的松耦合和灵活组合。此外,Spring 的源码中也注重代码的优雅性和简洁性,避免不必要的复杂性,让开发者在使用时更为自然和简便。

2. Holder或者Builder模式

在 Spring 源码中,像 BeanDefinitionHolder 这样的“持有者”类设计是一种非常经典的 封装和扩展 的实现方式。直接使用 BeanDefinition 确实可以完成很多任务,但引入类似 HolderBuilder 的类有以下几个重要的设计理由和优势:

2.1. 语义明确

BeanDefinitionHolder 不仅是对 BeanDefinition 的简单封装,还提供了更明确的语义。例如:

  • BeanDefinition 主要描述了一个 Bean 的定义(包括其属性、作用域等)。
  • BeanDefinitionHolder 除了持有 BeanDefinition 本身,还关联了 Bean 的名字和别名。

通过这种设计,可以让代码表达更清晰,传递的信息更完整。例如,BeanDefinitionHolder 在注册阶段不仅描述了 Bean 的定义,还包含了 Bean 的命名信息(name 和 aliases),这些是 BeanDefinition 本身没有涵盖的内容。

2.2. 分离职责

将数据和逻辑分离是优秀设计的重要原则之一:

  • BeanDefinition 负责描述 Bean 的元数据。
  • BeanDefinitionHolder 负责在某些场景下对 BeanDefinition 的附加包装(例如在注册和处理阶段传递额外的上下文信息)。

这种分离让每个类的职责更单一,便于维护和扩展。

2.3. 扩展性

在实际开发中,我们可能需要给核心对象(例如 BeanDefinition)附加额外的元信息。使用 Holder 模式,可以轻松扩展,而不需要修改核心对象的定义。例如:

  • 场景 1:在解析 XML 配置时,可能需要记录 Bean 的别名。
  • 场景 2:在后续注册 Bean 时,可能需要附加一些动态生成的属性。

如果直接修改 BeanDefinition 本身,会导致核心类变得臃肿,且影响范围过大。通过使用 BeanDefinitionHolder,可以在不破坏 BeanDefinition 原有设计的情况下,灵活扩展功能。

2.4. 中间状态的存储

Spring 在 Bean 定义的解析、注册、实例化等过程中,会经历多个步骤和阶段。在这些过程中,Holder 类可以帮助存储对象的“中间状态”或“上下文信息”,以便在不同阶段传递。

例如:

  • 在解析 Bean 的时候,可以用 BeanDefinitionHolder 包装一个 BeanDefinition,并附加其上下文信息(如 Bean 名称)。
  • BeanDefinition 进入注册阶段时,这些附加信息(如别名)可能会被处理掉,而 BeanDefinition 本身仍然保持纯净。

2.5. 方便对象的包装和增强

Holder 类可以方便地为核心对象添加额外的逻辑或功能,而不需要直接修改核心类。例如,BeanDefinitionHolder 在注册阶段可能会被用来代理或增强某些逻辑,而这些增强是透明的,对 BeanDefinition 本身没有影响。

2.6. 降低耦合性

如果直接在某些方法中使用 BeanDefinition,而方法内部需要额外的字段(如名字或别名),就需要对 BeanDefinition 增加依赖字段。但通过 Holder 类,字段和功能的扩展不会侵入核心类。

2.7. Builder 模式的构建

类似 ****Builder 的类,比如 BeanDefinitionBuilder,通常用于简化对象的创建。相比直接创建对象,Builder 模式有以下优点:

  • 链式调用:可以通过链式调用逐步设置属性,提高代码的可读性。
  • 避免构造函数的复杂性:如果某对象有多个属性需要设置,直接通过构造函数可能会导致参数列表过长,而 Builder 模式可以避免这种问题。
  • 构建过程分离Builder 让构建逻辑和对象本身分离,便于维护。

示例:BeanDefinitionHolder 的实际使用

定义阶段

在 Spring 的 Bean 工厂中注册 Bean 时,会使用 BeanDefinitionHolder

BeanDefinition beanDefinition = new RootBeanDefinition(MyClass.class);
BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDefinition, "myBean", new String[]{"alias1", "alias2"});

注册阶段

BeanDefinitionHolder 帮助携带额外信息,例如:

  • Bean 的名称(myBean
  • Bean 的别名(alias1, alias2

当将 Bean 注册到工厂时,可以通过 Holder 一次性传递完整信息。

2.8 总结

Spring 中使用 HolderBuilder 的设计模式,体现了优秀的面向对象设计思想:

  1. 提高了代码的扩展性和灵活性。
  2. 分离了对象的核心职责和扩展功能。
  3. 提供了更清晰的语义,使代码更易读、易维护。

直接使用核心类(如 BeanDefinition)虽然简单,但会导致职责混乱、不便扩展。因此,引入类似 BeanDefinitionHolder 的封装类是一种更优雅、更健壮的设计方式。

文档信息

Search

    Table of Contents