基于配置动态创建N个DynamicStringMaker Bean的实现难题
基于数组配置批量创建Named Bean的Spring Boot解决方案
问题背景
需要根据数组格式的配置项,批量创建N个DynamicStringMaker类型的Bean,该代码会被打包成依赖供其他应用调用,同时要通过@ConditionalOnProperty做启用控制。
按照现有方案实现时遇到两个问题:
- 要么必须始终创建
myBeansListBean,哪怕实际不会用到它 - 要么得在某处注入这个Bean但完全用不上它
尝试改用@PostConstruct注解后,命名Bean无法正常创建,导致使用时出现空指针,或者应用直接启动失败(无论required设为true还是false)
有两个示例版本:
- 未正常运行版本:Bean方法从未被执行
- 正常运行版本:通过自动注入数组实现
解决方案
利用Spring的BeanDefinitionRegistryPostProcessor接口,在Spring解析Bean定义的早期阶段动态注册Bean,既能避免不必要的Bean创建,又能完美适配条件注解的控制。
具体实现步骤
- 让配置类实现
BeanDefinitionRegistryPostProcessor接口,重写postProcessBeanDefinitionRegistry方法 - 在该方法中读取数组配置,为每个配置项创建
BeanDefinition并注册到容器中 - 添加
@ConditionalOnProperty注解控制整个配置类的启用状态 - 移除不必要的
@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
相关产品推荐
相关产品推荐

