Spring中如何基于列表创建多个@Configuration类实例?
解决方案
要实现基于列表创建多个独立的MyConfig配置实例(每个实例绑定对应的myBean4),不能直接通过new实例化,需要利用Spring的动态Bean注册机制,结合构造注入来实现每个配置实例的独立性。以下是具体步骤和代码示例:
步骤1:改造MyConfig类
首先修改MyConfig,移除无参构造,改用构造注入接收myBean4和实例标识(用于生成唯一Bean名称,避免冲突),同时保留@Configuration注解并关闭代理(确保每个实例独立):
@Configuration(proxyBeanMethods = false) public class MyConfig { private final CustomBean1 mybean1; private final CustomBean4 myBean4; private final String instanceId; // 构造注入所有依赖,包括专属的myBean4和实例唯一标识 public MyConfig(CustomBean1 mybean1, CustomBean4 myBean4, String instanceId) { this.mybean1 = mybean1; this.myBean4 = myBean4; this.instanceId = instanceId; } // 生成唯一命名的CustomBean3实例,避免Bean名称冲突 @Bean(name = "myChannel_#{this.instanceId}") public CustomBean3 myChannel() { return new CustomBean3(); } // 绑定当前实例的myChannel,同时可使用myBean4逻辑 @Bean public CustomBean2 getBean2(@Qualifier("myChannel_#{this.instanceId}") CustomBean3 myChannel) { CustomBean2 bean2 = new CustomBean2(); // 这里可以使用当前实例的myBean4进行初始化或业务处理 bean2.setDependency(myBean4); bean2.setChannel(myChannel); return bean2; } // 监听当前实例专属的channel @ServiceActivator(inputChannel = "myChannel_#{this.instanceId}") public void myReciever(@Header("abc") SomeBean bean) { // 业务逻辑中可直接使用当前实例的myBean4 myBean4.process(bean); } }
步骤2:动态注册MyConfig实例
实现BeanDefinitionRegistryPostProcessor,在Spring启动阶段遍历myBean4列表,为每个myBean4注册独立的MyConfig Bean定义:
@Component public class MyConfigDynamicRegistrar implements BeanDefinitionRegistryPostProcessor { // 注入myBean4列表(可从配置文件、数据库或其他Bean获取) private final List<CustomBean4> myBean4List; // 注入共享的CustomBean1 private final CustomBean1 customBean1; public MyConfigDynamicRegistrar(List<CustomBean4> myBean4List, CustomBean1 customBean1) { this.myBean4List = myBean4List; this.customBean1 = customBean1; } @Override public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException { for (int index = 0; index < myBean4List.size(); index++) { CustomBean4 targetBean4 = myBean4List.get(index); String instanceId = "instance_" + index; String configBeanName = "myConfig_" + instanceId; // 创建MyConfig的Bean定义 GenericBeanDefinition configBeanDef = new GenericBeanDefinition(); configBeanDef.setBeanClass(MyConfig.class); // 设置构造参数:customBean1、当前myBean4、实例唯一标识 configBeanDef.getConstructorArgumentValues().addIndexedArgumentValue(0, customBean1); configBeanDef.getConstructorArgumentValues().addIndexedArgumentValue(1, targetBean4); configBeanDef.getConstructorArgumentValues().addIndexedArgumentValue(2, instanceId); // 注册到Spring容器 registry.registerBeanDefinition(configBeanName, configBeanDef); } } @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { // 无需额外处理,留空即可 } }
关键说明
- 实例独立性:通过
proxyBeanMethods = false关闭@Configuration的CGLIB代理,确保每个MyConfig实例的@Bean方法都生成独立的Bean,不会共享实例。 - 唯一Bean命名:利用
instanceId为每个实例的myChannel、CustomBean2生成唯一名称,避免Spring容器内的Bean名称冲突。 - 构造注入:所有依赖(包括专属的
myBean4)通过构造注入,确保每个MyConfig实例持有自己的myBean4引用,实现业务隔离。 - 动态注册时机:
BeanDefinitionRegistryPostProcessor在Spring Bean定义注册阶段执行,能在容器初始化前完成所有MyConfig实例的注册,保证后续Bean创建流程正常执行。
内容的提问来源于stack exchange,提问作者Puneet Garg
相关产品推荐
相关产品推荐

