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

如何在Spring中手动注册非规则类(如构建器模式类)的Bean?

解决Spring中注册构建器模式类的多实例Bean问题

你说的这个问题确实戳中了Spring Bean注册的一个常见痛点:常规JavaBean因为遵循了 getter/setter 规范,用BeanDefinitionBuilder或者直接定义BeanDefinition都能顺利加载;但对于采用构建器模式实现的类(比如用Lombok @Builder生成的类,或者自定义的Builder),因为没有暴露公开的setter方法,Spring的常规Bean解析逻辑就失效了。而beanFactory.registerSingleton()又只能注册单实例,没法满足同一类下多个不同名称实例的需求。

下面给你两种实用的解决方案,都能完美解决这个问题:

方案一:使用InstanceSupplier自定义实例化逻辑

Spring从5.0开始支持通过InstanceSupplier来指定Bean的实例化方式,这完全绕开了对setter方法的依赖,你可以直接在Supplier里用构建器创建实例,并且每个BeanDefinition可以对应不同的配置,注册成不同名称的Bean。

举个代码例子:

// 假设你的构建器模式类是这样的
public class CustomBean {
    private final String name;
    private final int age;

    private CustomBean(Builder builder) {
        this.name = builder.name;
        this.age = builder.age;
    }

    public static Builder builder() {
        return new Builder();
    }

    public static class Builder {
        private String name;
        private int age;

        public Builder name(String name) {
            this.name = name;
            return this;
        }

        public Builder age(int age) {
            this.age = age;
            return this;
        }

        public CustomBean build() {
            return new CustomBean(this);
        }
    }
}

// 注册两个不同名称的CustomBean实例
GenericBeanDefinition beanDef1 = new GenericBeanDefinition();
beanDef1.setBeanClass(CustomBean.class);
// 用Supplier指定实例化逻辑
beanDef1.setInstanceSupplier(() -> CustomBean.builder().name("Bean1").age(20).build());
beanFactory.registerBeanDefinition("customBean1", beanDef1);

GenericBeanDefinition beanDef2 = new GenericBeanDefinition();
beanDef2.setBeanClass(CustomBean.class);
beanDef2.setInstanceSupplier(() -> CustomBean.builder().name("Bean2").age(30).build());
beanFactory.registerBeanDefinition("customBean2", beanDef2);

这种方式的好处是简洁直接,不需要额外的类,适合大多数场景。

方案二:自定义FactoryBean封装实例化逻辑

如果你的构建器初始化逻辑比较复杂(比如需要依赖其他Spring Bean、做额外的校验等),可以用Spring的FactoryBean扩展点来封装。FactoryBean本身是一个常规Bean,Spring可以处理它的setter方法,然后通过它的getObject()方法来创建目标Bean实例。

代码示例:

// 自定义FactoryBean来创建CustomBean
public class CustomBeanFactoryBean implements FactoryBean<CustomBean> {
    // 这里的属性可以通过setter配置,Spring能识别
    private String name;
    private int age;

    public void setName(String name) {
        this.name = name;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public CustomBean getObject() throws Exception {
        // 在这里用构建器创建实例
        return CustomBean.builder().name(name).age(age).build();
    }

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

// 注册两个不同的实例
BeanDefinitionBuilder builder1 = BeanDefinitionBuilder.genericBeanDefinition(CustomBeanFactoryBean.class);
builder1.addPropertyValue("name", "Bean1");
builder1.addPropertyValue("age", 20);
beanFactory.registerBeanDefinition("customBean1", builder1.getBeanDefinition());

BeanDefinitionBuilder builder2 = BeanDefinitionBuilder.genericBeanDefinition(CustomBeanFactoryBean.class);
builder2.addPropertyValue("name", "Bean2");
builder2.addPropertyValue("age", 30);
beanFactory.registerBeanDefinition("customBean2", builder2.getBeanDefinition());

这种方式的优势是扩展性强,能处理更复杂的初始化场景,而且可以复用FactoryBean的逻辑。

这两种方案都能满足你“注册同一类但不同名称的多个Bean”的需求,你可以根据自己的场景选择合适的方式。

内容的提问来源于stack exchange,提问作者Tommy.Tesla

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 07:07:18