soo*_*892 7 java spring spring-boot
我正在使用最新的 Spring Boot 版本,并尝试根据文件中定义的内容动态创建 n 个 bean application.yaml。然后我想根据 bean 名称将这些 bean 注入到其他类中。
下面的代码是我想要实现的目标的一个非常简化的示例。自动配置通常是 spring boot starter 库的一部分,因此需要注册的 bean 数量未知。
@Slf4j
@Value
public class BeanClass {
private final String name;
public void logName() {
log.info("Name: {}", name);
}
}
Run Code Online (Sandbox Code Playgroud)
@Component
@RequiredArgsConstructor
public class ServiceClass {
private final BeanClass fooBean;
private final BeanClass barBean;
public void log() {
fooBean.logName();
barBean.logName();
}
}
Run Code Online (Sandbox Code Playgroud)
@Value
@ConfigurationProperties
public class BeanProperties {
private final List<String> beans;
}
Run Code Online (Sandbox Code Playgroud)
@Configuration
public class AutoConfiguration {
// Obviously not correct
@Bean
public List<BeanClass> beans(final BeanProperties beanProperties) {
return beanProperties.getBeans().stream()
.map(BeanClass::new)
.collect(Collectors.toList());
}
}
Run Code Online (Sandbox Code Playgroud)
@EnableConfigurationProperties(BeanProperties.class)
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
final ConfigurableApplicationContext context = SpringApplication.run(DemoApplication.class, args);
final ServiceClass service = context.getBean(ServiceClass.class);
service.log();
}
}
Run Code Online (Sandbox Code Playgroud)
beansToMake:
- fooBean
- barBean
Run Code Online (Sandbox Code Playgroud)
我在谷歌上尝试了多种建议,但没有任何效果,而且似乎已经过时了。我希望 Spring 的一个新功能能让这一切变得简单。
Ton*_*oni 11
您可以实现BeanDefinitionRegistryPostProcessor接口来注册BeanClassbean 的定义,如下所示:
public class DynamicBeanDefinitionRegistrar implements BeanDefinitionRegistryPostProcessor {
public static final String PROPERTIES_PREFIX = "beans";
private final List<String> beanNames;
public DynamicBeanDefinitionRegistrar(Environment environment) {
beanNames =
Binder.get(environment)
.bind(PROPERTIES_PREFIX, Bindable.listOf(String.class))
.orElseThrow(IllegalStateException::new);
}
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry)
throws BeansException {
beanNames.forEach(
beanName -> {
GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
beanDefinition.setBeanClass(BeanClass.class);
beanDefinition.setInstanceSupplier(() -> new BeanClass(beanName));
registry.registerBeanDefinition(beanName, beanDefinition);
});
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
throws BeansException {}
}
Run Code Online (Sandbox Code Playgroud)
由于在实例化 bean 之前需要属性,因此注册BeanClassbean 的定义@ConfigurationProperties不适合这种情况。相反,Binder API用于以编程方式绑定它们。
根据Spring 文档,由于BeanFactoryPostProcessor对象通常必须在容器生命周期的早期实例化,因此@Bean应在类中将方法标记为静态@Configuration以避免生命周期问题。
@Configuration
public class DynamicBeanDefinitionRegistrarConfiguration {
@Bean
public static DynamicBeanDefinitionRegistrar beanDefinitionRegistrar(Environment environment) {
return new DynamicBeanDefinitionRegistrar(environment);
}
}
Run Code Online (Sandbox Code Playgroud)
因此,您在 中定义的所有 beanapplication.yml都会注册为BeanClassbeans:
beans:
- fooBean
- barBean
Run Code Online (Sandbox Code Playgroud)
供参考:使用 BeanDefinitionRegistryPostProcessor 创建 N 个 bean,Spring Boot Dynamic Bean Creation From Properties File
| 归档时间: |
|
| 查看次数: |
5403 次 |
| 最近记录: |