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

基于配置动态创建N个DynamicStringMaker Bean的实现难题

基于数组配置批量创建Named Bean的Spring Boot解决方案

问题背景

需要根据数组格式的配置项,批量创建N个DynamicStringMaker类型的Bean,该代码会被打包成依赖供其他应用调用,同时要通过@ConditionalOnProperty做启用控制。

按照现有方案实现时遇到两个问题:

  • 要么必须始终创建myBeansList Bean,哪怕实际不会用到它
  • 要么得在某处注入这个Bean但完全用不上它

尝试改用@PostConstruct注解后,命名Bean无法正常创建,导致使用时出现空指针,或者应用直接启动失败(无论required设为true还是false)

有两个示例版本:

  • 未正常运行版本:Bean方法从未被执行
  • 正常运行版本:通过自动注入数组实现

解决方案

利用Spring的BeanDefinitionRegistryPostProcessor接口,在Spring解析Bean定义的早期阶段动态注册Bean,既能避免不必要的Bean创建,又能完美适配条件注解的控制。

具体实现步骤

  1. 让配置类实现BeanDefinitionRegistryPostProcessor接口,重写postProcessBeanDefinitionRegistry方法
  2. 在该方法中读取数组配置,为每个配置项创建BeanDefinition并注册到容器中
  3. 添加@ConditionalOnProperty注解控制整个配置类的启用状态
  4. 移除不必要的@Bean方法和@PostConstruct逻辑,避免无效Bean的创建

完整代码示例

配置类代码

package uk.co.iamsimonsmale.facades.DynmicString.autoconfigure;

import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;

import uk.co.iamsimonsmale.facades.DynmicString.DynamicStringMaker;
import uk.co.iamsimonsmale.facades.DynmicString.ConfigurationProperties.Multi;
import uk.co.iamsimonsmale.facades.DynmicString.ConfigurationProperties.Single;

@Configuration
@EnableConfigurationProperties(Multi.class)
@ConditionalOnProperty(prefix = "uk.co.iamsimonsmale.dynamic-strings", name = "enabled", havingValue = "true", matchIfMissing = false)
public class MultiDynamicStringsConfig implements BeanDefinitionRegistryPostProcessor {

    private final Multi multiConfig;

    public MultiDynamicStringsConfig(Multi multiConfig) {
        this.multiConfig = multiConfig;
    }

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
        for (Single config : multiConfig.configs()) {
            BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(DynamicStringMaker.class)
                    .addConstructorArgValue(multiConfig.lastName())
                    .addConstructorArgValue(config.firstName());
            
            registry.registerBeanDefinition(config.beanName(), builder.getBeanDefinition());
        }
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
        // 无需额外操作,留空即可
    }
}

配置文件示例

uk.co.iamsimonsmale.dynamic-strings:
  enabled: true
  lastName: Smale
  configs:
    - beanName: simonBean
      firstName: Simon
    - beanName: griffinBean
      firstName: Griffin

关键优势

  • 完全通过@ConditionalOnProperty控制整个配置的启用,不会创建任何无效Bean
  • 直接在Bean定义阶段注册Named Bean,避免了@PostConstruct或额外Bean方法带来的问题
  • 依赖注入完全符合Spring生命周期,不会出现空指针或启动失败的情况

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 11:15:02