Spring 容器类型

最后更新: 2023-12-14 04:20:44 +0800 +0800
原文以英文撰写。您正在阅读AI翻译版本。

Spring 的容器 API 有三个不同层次:Bean 元数据、根据元数据创建对象的工厂,以及将工厂与应用程序服务协调起来的应用程序上下文。保持这些层次分离,可以更容易地理解 Spring 源代码和扩展点。

Bean 定义和注册表 #

BeanDefinition 是一个 Bean 的可变元数据。它记录 Bean 类或类名、作用域、构造函数参数、属性值、限定符、工厂方法、生命周期方法、角色、源位置和显式依赖。父子元数据关系独立于 Java 继承。

常见实现服务于不同的注册路径:

  • RootBeanDefinition 表示 Bean 工厂使用的合并定义。
  • ChildBeanDefinition 从命名的父定义继承元数据。
  • GenericBeanDefinition 可以在合并前表达独立或派生自父定义的元数据。
  • AnnotatedGenericBeanDefinition 公开已注册类的注解元数据。
  • ScannedGenericBeanDefinition 公开类路径扫描期间读取的元数据,而无需先加载组件类。

BeanDefinitionRegistry 按 Bean 名称存储定义。其核心操作是注册、移除和查询定义;DefaultListableBeanFactory 和 GenericApplicationContext 是重要实现。

AnnotatedBeanDefinitionReader 注册显式提供的组件类:

java
var context = new GenericApplicationContext();
var reader = new AnnotatedBeanDefinitionReader(context);
reader.register(OrderService.class);
context.refresh();

ClassPathBeanDefinitionScanner 搜索候选组件的包并注册其定义。两种机制都会应用注解作用域、命名、限定符、条件和 BeanDefinitionCustomizer 回调。定制器可以在注册期间进行有针对性的元数据更改,而无需实现注册表后处理器。

BeanFactory、FactoryBean 和 ObjectFactory #

BeanFactory 是运行时注册表和依赖解析 API。它定位定义、创建 Bean、解析协作者、管理单例身份并应用生命周期处理器。ListableBeanFactory 增加枚举功能,HierarchicalBeanFactory 增加父级查找,ConfigurableListableBeanFactory 向框架基础设施公开容器配置。应用程序代码应依赖领域协作者,而不是将 getBean() 作为服务定位器调用。

三个名称相似的类型具有不同职责:

  • BeanFactory 是容器。
  • FactoryBean<T> 是创建另一个对象的 Bean。查找其名称会返回产品;在名称前加 & 会返回工厂本身。getObjectType() 和 isSingleton() 描述产品。
  • ObjectFactory<T> 是带有 getObject() 的最小回调。Spring 使用它进行延迟获取和内部创建回调。ObjectProvider<T> 扩展了该模型,提供可选、有序和基于流的访问。

应用程序上下文层次结构 #

ApplicationContext 扩展 ListableBeanFactory、HierarchicalBeanFactory、MessageSource、ApplicationEventPublisher、ResourcePatternResolver 和相关环境能力。ConfigurableApplicationContext 增加 refresh()、close()、环境配置以及访问可配置工厂等生命周期操作。

AbstractApplicationContext 实现刷新算法。专用基类决定定义如何到达工厂:

  • GenericApplicationContext 拥有一个内部 DefaultListableBeanFactory。可以在一次 refresh() 调用前通过其注册表 API 注册定义。
  • AnnotationConfigApplicationContext 将通用上下文与 AnnotatedBeanDefinitionReader 和 ClassPathBeanDefinitionScanner 结合。其构造函数可以注册类或扫描包,然后刷新。
  • 支持 Servlet 的上下文增加 Web 作用域和 Servlet 资源,但保留相同的核心工厂契约。

某些较旧的上下文实现会在刷新期间重新创建 Bean 工厂,而 GenericApplicationContext 不支持重复刷新尝试。框架扩展必须遵循具体上下文的生命周期,而不是假设每个上下文都可以刷新多次。

刷新和生成的定义 #

注解注册最初会为提供的类创建定义。在刷新期间,ConfigurationClassPostProcessor 解析 @Configuration、组件扫描、导入和 @Bean 方法,然后在实例化普通 Bean 之前注册其他定义。注册表后处理器可以在同一阶段生成更多定义。Spring 的 AOT 处理可以提前生成注册代码,但生成的定义仍然进入相同的 Bean 工厂模型。

ApplicationStartup 会对启动进行检测,但不改变生命周期语义。DefaultApplicationStartup 是低开销的空操作实现,BufferingApplicationStartup 保留有界步骤数据,FlightRecorderApplicationStartup 发出 Java Flight Recorder 事件。StartupStep 具有名称、标签和明确的结束;自定义基础设施应保持标签成本低廉,因为启动检测运行在关键路径上。

选择扩展点 #

使用与需求匹配的最窄层次:

  1. 使用 BeanDefinitionCustomizer 在注册时定制定义。
  2. 使用 BeanDefinitionRegistryPostProcessor 或 BeanFactoryPostProcessor 添加或转换元数据。
  3. 使用 BeanPostProcessor 拦截实例。
  4. 使用 FactoryBean 构建产生对象的 Bean。
  5. 在 GenericApplicationContext 或应用程序上下文子类型上构建完整的协调容器。

主要参考资料 #

评论

在 GitHub 上阅读或评论(发表评论需要登录)