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

如何通过@Autowired+@Qualifier注入运行时动态创建的Spring Bean?

解决方案:动态注册Bean并支持@Autowired+@Qualifier注入

问题分析

你当前的代码存在两个核心问题:

  1. ApplicationContextAware实现中重复注册同一Bean名称的实例,导致最终仅保留最后一次循环的Bean
  2. 对BeanDefinitionRegistryPostProcessor的使用存在误解,实际上它完全可以读取TestProperties中的Map属性

以下提供两种可行方案,推荐使用方案2(符合Spring规范的Bean注册方式)。


方案1:修复现有ApplicationContextAware实现

registerSingleton注册的单例Bean本身是可以被@Autowired识别的,问题出在你的循环逻辑错误。修复后即可正常使用@Autowired+@Qualifier注入。

修复后的代码

@Configuration
public class DynamicBeanConfiguration implements ApplicationContextAware {

    private final TestProperties testProperties;

    public DynamicBeanConfiguration(TestProperties testProperties) {
        this.testProperties = testProperties;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        ConfigurableApplicationContext configurableCtx = (ConfigurableApplicationContext) applicationContext;
        ConfigurableListableBeanFactory beanFactory = configurableCtx.getBeanFactory();

        for (Map.Entry<String, Properties> entry : testProperties.getProperties().entrySet()) {
            String beanName = entry.getKey();
            Properties serviceProps = entry.getValue();

            // 每个服务仅创建一个Bean实例
            TestDynamicBean dynamicBean = beanFactory.createBean(
                TestDynamicBean.class, 
                AutowireCapableBeanFactory.AUTOWIRE_BY_NAME, 
                false
            );
            dynamicBean.setServiceName(beanName);
            
            // 处理属性(这里示例取第一个属性,可根据需求调整为批量处理)
            if (!serviceProps.isEmpty()) {
                Map.Entry<Object, Object> firstProp = serviceProps.entrySet().iterator().next();
                dynamicBean.setValue(firstProp.getValue().toString());
            }

            beanFactory.autowireBean(dynamicBean);
            // 仅注册一次该Bean名称的实例
            beanFactory.registerSingleton(beanName, dynamicBean);
        }
    }
}

注意事项

  • 确保注入时机:不要在@PostConstruct或更早阶段注入动态Bean,需等待上下文刷新完成
  • TestProperties必须正确绑定配置,需添加@ConfigurationProperties(prefix = "config")注解

方案2:使用BeanDefinitionRegistryPostProcessor注册Bean(推荐)

这是Spring官方推荐的动态注册Bean方式,生成完整的BeanDefinition,完美支持@Autowired+@Qualifier注入,且能正常读取TestProperties的Map属性。

实现动态Bean注册处理器

@Component
public class DynamicBeanDefinitionProcessor implements BeanDefinitionRegistryPostProcessor {

    private final TestProperties testProperties;

    // 构造注入已绑定配置的TestProperties实例
    public DynamicBeanDefinitionProcessor(TestProperties testProperties) {
        this.testProperties = testProperties;
    }

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        for (Map.Entry<String, Properties> entry : testProperties.getProperties().entrySet()) {
            String beanName = entry.getKey();
            Properties serviceProps = entry.getValue();

            // 创建BeanDefinition并配置属性
            GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
            beanDefinition.setBeanClass(TestDynamicBean.class);
            beanDefinition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_NAME);

            MutablePropertyValues propertyValues = new MutablePropertyValues();
            propertyValues.add("serviceName", beanName);
            if (!serviceProps.isEmpty()) {
                Map.Entry<Object, Object> firstProp = serviceProps.entrySet().iterator().next();
                propertyValues.add("value", firstProp.getValue().toString());
            }
            beanDefinition.setPropertyValues(propertyValues);

            // 注册BeanDefinition到上下文
            registry.registerBeanDefinition(beanName, beanDefinition);
        }
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        // 无需额外操作,如需修改已注册BeanDefinition可在此处理
    }
}

调整自动配置类

@Configuration
@EnableConfigurationProperties(TestProperties.class)
public class TestAutoConfiguration {

    @Bean
    public DynamicBeanDefinitionProcessor dynamicBeanDefinitionProcessor(TestProperties properties) {
        return new DynamicBeanDefinitionProcessor(properties);
    }
}

配套TestProperties定义

确保配置绑定类正确实现:

@ConfigurationProperties(prefix = "config")
public class TestProperties {
    private Map<String, Properties> properties;

    // Getter & Setter
    public Map<String, Properties> getProperties() {
        return properties;
    }

    public void setProperties(Map<String, Properties> properties) {
        this.properties = properties;
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 03:21:31