深入Spring FactoryBean:揭秘factoryBeanObjectCache的存储机制

本文基于Spring 5.3.33源码解析,带你从浅入深探索FactoryBean的核心机制,重点剖析factoryBeanObjectCache的运作原理,并揭示SmartFactoryBean的高级特性。

一、FactoryBean:Spring中的对象工厂

1.1 FactoryBean基础概念

FactoryBean是Spring框架中一种特殊类型的Bean,它本身不直接提供功能,而是负责创建其他Bean的实例。这种设计模式在Spring中被广泛应用,尤其适用于复杂对象的创建场景。

public interface FactoryBean<T> {
    // 返回工厂创建的对象实例
    T getObject() throws Exception;
    
    // 返回对象类型
    Class<?> getObjectType();
    
    // 是否为单例对象
    boolean isSingleton();
}

1.2 为何需要FactoryBean?

当遇到以下场景时,FactoryBean就大显身手了:

  • 创建过程复杂的对象(如数据库连接池)
  • 需要动态决定对象类型的场景
  • 需要封装第三方库的初始化过程
  • 对象创建需要特殊配置

二、factoryBeanObjectCache:核心存储容器

2.1 神秘的缓存容器

在Spring源码深处,隐藏着一个关键缓存容器——factoryBeanObjectCache。这个位于FactoryBeanRegistrySupport类中的缓存负责存储FactoryBean创建的对象实例。

// 源码位置:org.springframework.beans.factory.support.FactoryBeanRegistrySupport
public abstract class FactoryBeanRegistrySupport extends DefaultSingletonBeanRegistry {
    // FactoryBean创建的单例对象缓存
    private final Map<String, Object> factoryBeanObjectCache = new ConcurrentHashMap<>(16);
    
    // ... 其他代码
}

2.2 缓存的工作机制

当通过getBean()获取FactoryBean产品时,Spring会按以下逻辑处理:

存在
不存在
调用getBean'factoryBeanName'
是FactoryBean?
是否单例?
直接返回Bean
缓存中是否存在?
新建对象
返回缓存对象
创建对象并放入缓存

三、何时使用factoryBeanObjectCache?

3.1 缓存写入条件

对象会被存储到factoryBeanObjectCache中,当且仅当同时满足以下条件:

  1. FactoryBean是单例isSingleton()返回true)
  2. 当前作用域是单例(非原型作用域)
  3. 对象首次被创建

3.2 缓存读取流程

从源码角度看缓存读取过程:

// 源码位置:FactoryBeanRegistrySupport
protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName) {
    // 单例FactoryBean的处理
    if (factory.isSingleton() && containsSingleton(beanName)) {
        synchronized (getSingletonMutex()) {
            // 尝试从缓存获取
            Object object = this.factoryBeanObjectCache.get(beanName);
            if (object == null) {
                // 创建对象并放入缓存
                object = doGetObjectFromFactoryBean(factory, beanName);
                this.factoryBeanObjectCache.put(beanName, object);
            }
            return object;
        }
    }
    else {
        // 非单例情况直接创建新对象
        return doGetObjectFromFactoryBean(factory, beanName);
    }
}

3.3 不会缓存的情况

以下情况对象不会被缓存:

  1. 原型作用域的FactoryBean(每次请求都创建新对象)
    public boolean isSingleton() {
        return false; // 原型模式
    }
    
  2. FactoryBean本身是原型作用域
  3. 在Bean初始化过程中出现异常
  4. SmartFactoryBean指定不缓存(通过特殊配置)

四、SmartFactoryBean:更智能的工厂

4.1 升级版FactoryBean

SmartFactoryBean在基础FactoryBean上增加了更多控制能力:

public interface SmartFactoryBean<T> extends FactoryBean<T> {
    // 是否立即初始化(在应用启动时创建)
    default boolean isEagerInit() {
        return false;
    }
    
    // 是否原型对象(已废弃,使用作用域代替)
    @Deprecated
    default boolean isPrototype() {
        return false;
    }
}

4.2 高级特性解析

特性1:立即初始化(Eager Initialization)

设置isEagerInit()返回true时,Spring会在容器启动阶段就初始化该对象,而不是等到首次请求。

public class EagerInitFactoryBean implements SmartFactoryBean<MyBean> {
    @Override
    public boolean isEagerInit() {
        return true; // 容器启动时立即初始化
    }
    
    // 其他方法实现...
}
特性2:原型作用域控制

虽然isPrototype()方法已被废弃,但我们可以结合@Scope注解实现原型控制:

@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class PrototypeFactoryBean implements FactoryBean<PrototypeBean> {
    // 实现方法...
}

4.3 源码中的SmartFactoryBean

在Spring容器启动过程中,SmartFactoryBean会被特殊处理:

// 源码位置:AbstractApplicationContext
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
    // 处理SmartFactoryBean的立即初始化
    String[] smartFactoryNames = beanFactory.getBeanNamesForType(SmartFactoryBean.class);
    for (String name : smartFactoryNames) {
        SmartFactoryBean<?> smartFactory = (SmartFactoryBean<?>) beanFactory.getBean("&" + name);
        if (smartFactory.isEagerInit()) {
            // 触发立即初始化
            beanFactory.getBean(name);
        }
    }
}

五、FactoryBean的实战应用

5.1 典型使用场景

public class ConnectionFactoryBean implements FactoryBean<Connection> {
    private String url;
    private String username;
    private String password;
    
    @Override
    public Connection getObject() throws Exception {
        return DriverManager.getConnection(url, username, password);
    }
    
    // 其他方法实现...
}

5.2 性能优化建议

  1. 对于重量级对象使用单例FactoryBean+缓存
  2. 对于轻量级可变对象使用原型作用域
  3. 避免在getObject()中执行耗时操作
  4. 合理使用SmartFactoryBean的立即初始化特性

六、总结与思考

通过本文的探讨,我们深入理解了Spring FactoryBean的核心机制:

  1. factoryBeanObjectCache是存储单例FactoryBean产品的核心缓存
  2. 缓存使用遵循严格的单例双重检查逻辑
  3. SmartFactoryBean提供了更精细的控制能力
  4. 原型FactoryBean的产品不会进入缓存
  5. 立即初始化特性影响容器启动行为

最后思考一个问题:为什么Spring要设计factoryBeanObjectCache这个单独的缓存,而不是使用普通的单例缓存?

答案在于FactoryBean的特殊性。FactoryBean本身是一个Bean,而它创建的产品是另一个逻辑Bean。使用单独的缓存可以:

  • 清晰区分FactoryBean实例和它创建的产品
  • 避免循环依赖时的复杂情况
  • 支持特殊处理逻辑(如&前缀获取工厂本身)
// 获取FactoryBean本身(注意&前缀)
FactoryBean<?> factory = context.getBean("&myFactoryBean");

// 获取FactoryBean创建的产品
Object product = context.getBean("myFactoryBean");

理解FactoryBean的底层机制,能够帮助我们更好地设计复杂的Spring应用,优化性能,并避免潜在的陷阱。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值