You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring配置为单例的Service15通过FactoryBean创建却被初始化两次原因排查

问题成因
  • Spring 中实现了FactoryBean接口的类,其生产的单例对象会在getObject()方法正常返回后,才被存入Spring内部缓存,后续对该bean的请求才会直接复用缓存实例。
  • 你的代码存在循环依赖场景:Service16依赖Service15实例,而Service15Factory的getObject()方法中又主动调用beanFactory.getBean("service16")获取Service16实例。
  • 执行流程触发两次getObject()调用:
    1. 容器初始化Service16时,需要注入Service15属性,触发第一次getObject()调用
    2. getObject()内部执行getBean("service16")时,Service16还未完成属性注入,会再次触发Service15的获取请求
    3. 此时第一次getObject()还未执行完成,Spring缓存中还没有Service15实例,因此会第二次调用getObject(),创建第二个Service15实例
修复方案

方案1:自行缓存Service15实例

在Service15Factory中自行实现实例缓存,避免重复创建,改造成本最低:

public class Service15Factory implements FactoryBean, BeanFactoryAware {
    private BeanFactory beanFactory;
    // 缓存生产的Service15实例
    private Service15 service15;

    public Service15Factory(){
        System.out.println("serviceFactory15 init");
    }
    @Override
    public Object getObject() throws Exception {
        // 仅首次调用时创建实例
        if (service15 == null) {
            beanFactory.getBean("service16");
            service15 = new Service15();
        }
        return service15;
    }

    @Override
    public Class<?> getObjectType() {
        return Service15.class;
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
    }
}

方案2:调整Service16的获取时机

将Service16的获取逻辑从getObject()中移出,改为通过Spring注入的方式提前获取,更符合Spring使用规范:
修改Service15Factory代码:

public class Service15Factory implements FactoryBean {
    private Service16 service16;
    private Service15 service15;

    public Service15Factory(){
        System.out.println("serviceFactory15 init");
    }
    @Override
    public Object getObject() throws Exception {
        if (service15 == null) {
            service15 = new Service15();
        }
        return service15;
    }

    @Override
    public Class<?> getObjectType() {
        return Service15.class;
    }

    // 新增set方法,让Spring注入service16
    public void setService16(Service16 service16) {
        this.service16 = service16;
    }
}

修改XML配置,增加service16的注入声明:

<bean id="service15" class="com.myspring.service.Service15Factory" scope="singleton">
    <property name="service16" ref="service16"/>
</bean>
<bean id="service16" class="com.myspring.service.Service16">
    <property name="service15" ref="service15"></property>
</bean>

方案3:调整业务逻辑消除循环依赖

如果业务逻辑允许,直接移除getObject()中的beanFactory.getBean("service16")调用,从根源上避免循环获取场景。

内容的提问来源于stack exchange,提问作者chenzy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.07 06:45:04