深入探究 Spring 中 FactoryBean 注册服务的实现与原理

ops/2025/2/5 23:03:23/

深入探究 Spring 中 FactoryBean 注册服务的实现与原理

引言

在 Spring 框架里,FactoryBean 是一个强大且重要的特性。它允许开发者以一种更加灵活的方式来创建和管理 Bean 对象。FactoryBeanRegistrySupportAbstractBeanFactory 这两个类在处理 FactoryBean 相关操作时扮演着关键角色,它们共同协作完成了 FactoryBean 的注册、对象创建以及缓存管理等功能。接下来,我们将深入剖析这些类的实现细节和背后的设计理念。

1. 核心接口:FactoryBean

1.1 接口定义

interface FactoryBean<T> {T getObject() throws Exception;Class<?> getObjectType();boolean isSingleton();
}

1.2 详细解释

  • getObject() 方法:这是 FactoryBean 最核心的方法,它负责创建并返回具体的 Bean 对象。开发者可以在这个方法中编写复杂的对象创建逻辑,比如进行对象的初始化、依赖注入、资源加载等操作。例如,在一个数据库连接池的 FactoryBean 实现中,getObject() 方法可以创建并初始化一个数据库连接池实例。
  • getObjectType() 方法:该方法用于返回 getObject() 方法所创建对象的类型。Spring 框架在运行时可以通过这个方法获取对象的类型信息,从而进行类型检查和转换。比如,在进行 Bean 注入时,Spring 可以根据 getObjectType() 返回的类型来判断是否符合注入要求。
  • isSingleton() 方法:此方法用于指示 FactoryBean 创建的对象是否为单例。如果返回 true,则表示该对象是单例的,Spring 会对其进行缓存,后续的请求都会返回同一个对象实例;如果返回 false,则每次请求都会调用 getObject() 方法创建一个新的对象实例。

2. 基础支撑:DefaultSingletonBeanRegistry

2.1 类定义

class DefaultSingletonBeanRegistry {private final ConcurrentMap<String, Object> singletonObjects = new ConcurrentHashMap<>();protected Object getSingleton(String beanName) {return singletonObjects.get(beanName);}protected void addSingleton(String beanName, Object singletonObject) {singletonObjects.put(beanName, singletonObject);}
}

2.2 详细解释

  • singletonObjects 缓存:这是一个 ConcurrentHashMap,用于存储单例 Bean 对象。使用 ConcurrentHashMap 可以确保在多线程环境下对单例对象的访问是线程安全的,避免了并发访问时可能出现的数据不一致问题。
  • getSingleton(String beanName) 方法:该方法用于从 singletonObjects 缓存中获取指定名称的单例 Bean 对象。如果缓存中存在该对象,则直接返回;如果不存在,则返回 null
  • addSingleton(String beanName, Object singletonObject) 方法:此方法用于将一个单例 Bean 对象添加到 singletonObjects 缓存中。通过这种方式,Spring 可以在后续的请求中直接从缓存中获取该对象,而无需再次创建,提高了性能。

3. 关键类:FactoryBeanRegistrySupport

3.1 类定义

abstract class FactoryBeanRegistrySupport extends DefaultSingletonBeanRegistry {private static final Object NULL_OBJECT = new Object();/*** Cache of singleton objects created by FactoryBeans: FactoryBean name --> object*/private final ConcurrentMap<String, Object> factoryBeanObjectCache = new ConcurrentHashMap<>();protected Object getCachedObjectForFactoryBean(String beanName) {Object object = this.factoryBeanObjectCache.get(beanName);return (object != NULL_OBJECT ? object : null);}protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName) {if (factory.isSingleton()) {Object object = this.factoryBeanObjectCache.get(beanName);if (object == null) {object = doGetObjectFromFactoryBean(factory, beanName);this.factoryBeanObjectCache.put(beanName, (object != null ? object : NULL_OBJECT));}return (object != NULL_OBJECT ? object : null);} else {return doGetObjectFromFactoryBean(factory, beanName);}}private Object doGetObjectFromFactoryBean(final FactoryBean<?> factory, final String beanName) {try {return factory.getObject();} catch (Exception e) {throw new BeansException("FactoryBean threw exception on object[" + beanName + "] creation", e);}}
}

3.2 详细解释

3.2.1 factoryBeanObjectCache 缓存

这是一个专门用于缓存由 FactoryBean 创建的单例对象的 ConcurrentMap。键为 FactoryBean 的名称,值为 FactoryBean 创建的对象。使用这个缓存可以避免重复创建单例对象,提高性能。

3.2.2 getCachedObjectForFactoryBean(String beanName) 方法

该方法用于从 factoryBeanObjectCache 缓存中获取指定名称的 FactoryBean 创建的对象。如果缓存中存在该对象,则直接返回;如果缓存中存储的是 NULL_OBJECT,则表示该对象不存在,返回 null

3.2.3 getObjectFromFactoryBean(FactoryBean<?> factory, String beanName) 方法

这是一个核心方法,用于从 FactoryBean 中获取对象。如果 FactoryBean 创建的是单例对象,则先从 factoryBeanObjectCache 缓存中查找。如果缓存中不存在,则调用 doGetObjectFromFactoryBean 方法创建对象,并将其放入缓存中。如果 FactoryBean 创建的不是单例对象,则直接调用 doGetObjectFromFactoryBean 方法创建对象。

3.2.4 doGetObjectFromFactoryBean(FactoryBean<?> factory, String beanName) 方法

该方法直接调用 FactoryBeangetObject() 方法来创建对象。如果创建过程中出现异常,则抛出 BeansException 异常,将异常信息和原始异常一起封装,方便后续的错误处理和调试。

4. 核心抽象类:AbstractBeanFactory

4.1 类定义

abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory {protected <T> T doGetBean(final String name, final Object[] args) {Object sharedInstance = getSingleton(name);if (sharedInstance != null) {// 如果是 FactoryBean,则需要调用 FactoryBean#getObjectreturn (T) getObjectForBeanInstance(sharedInstance, name);}BeanDefinition beanDefinition = getBeanDefinition(name);Object bean = createBean(name, beanDefinition, args);return (T) getObjectForBeanInstance(bean, name);}private Object getObjectForBeanInstance(Object beanInstance, String beanName) {if (!(beanInstance instanceof FactoryBean)) {return beanInstance;}Object object = getCachedObjectForFactoryBean(beanName);if (object == null) {FactoryBean<?> factoryBean = (FactoryBean<?>) beanInstance;object = getObjectFromFactoryBean(factoryBean, beanName);}return object;}protected abstract BeanDefinition getBeanDefinition(String name);protected abstract Object createBean(String name, BeanDefinition beanDefinition, Object[] args);
}

4.2 详细解释

4.2.1 doGetBean(String name, Object[] args) 方法

这是获取 Bean 对象的核心方法。首先,它尝试从单例缓存中获取指定名称的 Bean 对象。如果缓存中存在该对象,则调用 getObjectForBeanInstance 方法进行处理,因为该对象可能是一个 FactoryBean,需要进一步获取其创建的对象。如果缓存中不存在该对象,则通过 getBeanDefinition 方法获取该 Bean 的定义信息,再调用 createBean 方法创建对象,最后同样调用 getObjectForBeanInstance 方法进行处理。

4.2.2 getObjectForBeanInstance(Object beanInstance, String beanName) 方法

该方法用于判断 beanInstance 是否为 FactoryBean 类型。如果不是,则直接返回该对象;如果是,则先从 factoryBeanObjectCache 缓存中获取 FactoryBean 创建的对象。如果缓存中不存在,则调用 getObjectFromFactoryBean 方法从 FactoryBean 中获取对象。

4.2.3 getBeanDefinition(String name)createBean(String name, BeanDefinition beanDefinition, Object[] args) 方法

这两个方法是抽象方法,需要在具体的子类中实现。getBeanDefinition 方法用于根据 Bean 的名称获取其定义信息,这些定义信息包含了 Bean 的各种属性和配置;createBean 方法用于根据 Bean 的定义信息创建具体的 Bean 对象,可能涉及到对象的实例化、属性注入、初始化等操作。

5. 示例 FactoryBean 实现类

5.1 类定义

class ExampleFactoryBean implements FactoryBean<String> {@Overridepublic String getObject() throws Exception {return "Example Object";}@Overridepublic Class<?> getObjectType() {return String.class;}@Overridepublic boolean isSingleton() {return true;}
}

5.2 详细解释

这个类实现了 FactoryBean 接口,用于创建一个 String 类型的对象。getObject() 方法返回一个固定的字符串 "Example Object",表示创建的对象内容。getObjectType() 方法返回 String.class,明确了创建对象的类型。isSingleton() 方法返回 true,表示该对象是单例的,Spring 会对其进行缓存,后续的请求都会返回同一个 "Example Object" 实例。

6. 测试类

6.1 类定义

public class FactoryBeanRegistrationTest {public static void main(String[] args) {AbstractBeanFactory beanFactory = new AbstractBeanFactory() {@Overrideprotected BeanDefinition getBeanDefinition(String name) {return new BeanDefinition();}@Overrideprotected Object createBean(String name, BeanDefinition beanDefinition, Object[] args) {if ("exampleFactoryBean".equals(name)) {return new ExampleFactoryBean();}return null;}};String exampleObject = beanFactory.doGetBean("exampleFactoryBean", null);System.out.println(exampleObject);}
}

6.2 详细解释

在这个测试类中,我们创建了一个 AbstractBeanFactory 的匿名子类,并重写了 getBeanDefinitioncreateBean 方法。getBeanDefinition 方法简单地返回一个新的 BeanDefinition 实例,实际应用中可以根据具体需求从配置文件或其他数据源中获取 Bean 的定义信息。createBean 方法根据 beanName 判断是否为 "exampleFactoryBean",如果是,则返回 ExampleFactoryBean 实例;否则返回 null。然后调用 doGetBean 方法获取 ExampleFactoryBean 创建的对象,并将其打印输出。通过这个测试,我们可以验证 FactoryBean 注册服务的功能是否正常。

7. 设计模式与应用场景

7.1 设计模式

  • 工厂模式FactoryBean 接口本身就是工厂模式的一种体现。通过实现 FactoryBean 接口,开发者可以将对象的创建逻辑封装在 getObject() 方法中,使得对象的创建和使用分离,提高了代码的可维护性和可扩展性。
  • 缓存模式FactoryBeanRegistrySupport 类中的 factoryBeanObjectCache 缓存和 DefaultSingletonBeanRegistry 类中的 singletonObjects 缓存都运用了缓存模式。缓存模式可以避免重复创建对象,提高系统的性能和响应速度。

7.2 应用场景

  • 复杂对象的创建:当需要创建的对象比较复杂,包含多个依赖项或需要进行复杂的初始化操作时,可以使用 FactoryBean 来封装对象的创建逻辑。例如,创建一个数据库连接池、线程池等。
  • 动态对象的创建:如果需要根据不同的条件动态创建对象,可以在 FactoryBeangetObject() 方法中编写动态创建逻辑。例如,根据配置文件中的参数创建不同类型的日志记录器。

8. 总结

通过对 FactoryBean 注册服务的深入分析,我们了解到 Spring 框架通过 FactoryBean 接口、FactoryBeanRegistrySupport 类和 AbstractBeanFactory 类的协作,提供了一种灵活、高效的对象创建和管理方式。FactoryBean 允许开发者自定义对象的创建逻辑,而 FactoryBeanRegistrySupport 负责对象的缓存和获取,AbstractBeanFactory 则在整个 Bean 生命周期中对 FactoryBean 进行了特殊处理。这种设计使得 Spring 框架能够满足各种复杂的应用场景,提高了系统的可维护性和可扩展性。在实际开发中,合理运用 FactoryBean 可以让我们更加灵活地管理对象的创建和使用,提升开发效率和代码质量。


http://www.ppmy.cn/ops/155994.html

相关文章

vue3中el-input无法获得焦点的问题

文章目录 现象两次nextTick()加setTimeout()解决结论 现象 el-input被外层div包裹了&#xff0c;设置autofocus不起作用&#xff1a; <el-dialog v-model"visible" :title"title" :append-to-bodytrue width"50%"><el-form v-model&q…

C++滑动窗口技术深度解析:核心原理、高效实现与高阶应用实践

目录 一、滑动窗口的核心原理 二、滑动窗口的两种类型 1. 固定大小的窗口 2. 可变大小的窗口 三、实现细节与关键点 1. 窗口的初始化 2. 窗口的移动策略 3. 结果的更新时机 四、经典问题与代码示例 示例 1&#xff1a;和 ≥ target 的最短子数组&#xff08;可变窗口…

python学opencv|读取图像(五十六)使用cv2.GaussianBlur()函数实现图像像素高斯滤波处理

【1】引言 前序学习了均值滤波和中值滤波&#xff0c;对图像的滤波处理有了基础认知&#xff0c;相关文章链接为&#xff1a; python学opencv|读取图像&#xff08;五十四&#xff09;使用cv2.blur()函数实现图像像素均值处理-CSDN博客 python学opencv|读取图像&#xff08;…

DeepSeek 的含金量还在上升

大家好啊&#xff0c;我是董董灿。 最近 DeepSeek 越来越火了。 网上有很多针对 DeepSeek 的推理测评&#xff0c;除此之外&#xff0c;也有很多人从技术的角度来探讨 DeepSeek 带给行业的影响。 比如今天就看到了一篇文章&#xff0c;探讨 DeepSeek 在使用 GPU 进行模型训练…

CNN的各种知识点(四): 非极大值抑制(Non-Maximum Suppression, NMS)

非极大值抑制&#xff08;Non-Maximum Suppression, NMS&#xff09; 1. 非极大值抑制&#xff08;Non-Maximum Suppression, NMS&#xff09;概念&#xff1a;算法步骤&#xff1a;具体例子&#xff1a;PyTorch实现&#xff1a; 总结&#xff1a; 1. 非极大值抑制&#xff08;…

Linux环境下的Java项目部署技巧:Nginx 详解

Nginx 的启动 Nginx 启动会生成 2 个进程&#xff1a;主进程与守护进程 主进程&#xff1a;常用于提供反向代理服务。特点&#xff1a;占内存大守护进程&#xff1a;防止主进程以外关闭。特点&#xff1a;占内存小 Nginx 启动需要占用 80 端口: 当 Ngnix 启动失败时&#xff0…

联想拯救者R720笔记本外接显示屏方法,显示屏是2K屏27英寸

现在某品牌的13/14代&#xff08;CPU是13或14开头&#xff09;CPU缩肛有设计质量问题、CPU容易氧化易损坏易蓝屏等问题&#xff0c;现在大家买笔记本或台式电脑请不要考虑这两代CPU&#xff0c;或考虑AMD的CPU。 晚上23点10分前下单&#xff0c;第二天上午显示屏送到&#xff…

Dest1ny攻防实战:SpringBoot 脱敏属性***明文获取

今天是dest1ny攻防实战&#xff01; 脱敏springboot敏感数据&#xff01;&#xff01; 大家多多支持&#xff0c;多多点赞&#xff0c;多多关注&#xff01;&#xff01; 谢谢大家&#xff0c;下面我们来看今天的内容&#xff01; 1.前言 SpringBoot敏感信息泄露&#xff0…