英文:
How to programmatically mark a spring bean as @Primary on startup?
问题
我在我的应用程序中有多个 DataSource
。
标准的 org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaConfiguration
被注解为 @ConditionalOnSingleCandidate(DataSource.class)
。
我试图以编程方式选择一个 @Primary
的 DataSource
。
我尝试过使用 BeanFactoryPostProcessor
来天真地选择第一个 DataSource
并标记为主要:
@Bean
public BeanFactoryPostProcessor beanFactoryPostProcessor() {
return this::setPrimaryDataSource;
}
public void setPrimaryDataSource(ConfigurableListableBeanFactory beanFactory) {
// 获取所有 DataSource 的 bean 名称
String[] dataSourceBeanNames = beanFactory.getBeanNamesForType(DataSource.class);
// 查找 primaryBeanName
String primaryBeanName = dataSourceBeanNames.length > 0 ? dataSourceBeanNames[0] : null;
// 返回适当的 bean
assert primaryBeanName != null;
BeanDefinition beanDefinition = beanFactory.getBeanDefinition(primaryBeanName);
beanDefinition.setPrimary(true);
LOGGER.info("Primary DataSource: {}", primaryBeanName);
}
然而,这似乎不起作用 - HibernateJpaConfiguration
上的 @ConditionalOnSingleCandidate(DataSource.class)
检查仍然失败。
是否有其他地方可以将此代码放置,以便在检查 @ConditionalOnSingleCandidate
之前执行它?
英文:
I have multiple DataSource
s in my application.
The standard org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaConfiguration
is annotated with @ConditionalOnSingleCandidate(DataSource.class)
I am attempting to select a @Primary
DataSource
programmatically.
I have tried a BeanFactoryPostProcessor
that naively selects the first DataSource and marks as primary):
@Bean
public BeanFactoryPostProcessor beanFactoryPostProcessor() {
return this::setPrimaryDataSource;
}
public void setPrimaryDataSource(ConfigurableListableBeanFactory beanFactory) {
// Get all DataSource bean names
String[] dataSourceBeanNames = beanFactory.getBeanNamesForType(DataSource.class);
// Find primaryBeanName
String primaryBeanName = dataSourceBeanNames.length > 0 ? dataSourceBeanNames[0] : null;
// Return appropriate bean
assert primaryBeanName != null;
BeanDefinition beanDefinition = beanFactory.getBeanDefinition(primaryBeanName);
beanDefinition.setPrimary(true);
LOGGER.info("Primary DataSource: {}", primaryBeanName);
}
However, this does not appear to work - the @ConditionalOnSingleCandidate(DataSource.class)
check on HibernateJpaConfiguration
still fails.
Is there anywhere else I can put this code such that it will be executed before the check for @ConditionalOnSingleCandidate
?
答案1
得分: 2
`BeanFactoryPostProcessor` 对我起了作用:
@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
// 检索您的 bean 名称的逻辑
String beanName = beanFactory.getBeanNamesForType(MyService.class)[0];
BeanDefinition bd = beanFactory.getBeanDefinition(beanName);
bd.setPrimary(true);
}
}
英文:
BeanFactoryPostProcessor
worked for me:
@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
// logic to retrieve your bean name
String beanName = beanFactory.getBeanNamesForType(MyService.class)[0];
BeanDefinition bd = beanFactory.getBeanDefinition(beanName);
bd.setPrimary(true);
}
}
答案2
得分: 1
如果您的代码位于带有@Configuration的类中,则该方法需要是静态的,以便在任何bean创建之前更新bean定义。
以下是PropertySourcesPlaceholderConfigurer的示例。
@Configuration
public class AppConfig {
@Bean
public static PropertySourcesPlaceholderConfigurer propertyPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
}
在文档中:
> 您可以将@Bean方法声明为静态方法,允许在不创建包含其配置类实例的情况下调用它们。这在定义后置处理器bean时特别有意义(例如,BeanFactoryPostProcessor或BeanPostProcessor类型的bean),因为这些bean在容器生命周期的早期进行初始化,应避免在该点触发配置的其他部分。
英文:
If your code is in a class with @Configuration, the method need to be static in order to update the bean definition before any bean creation.
Here is a sample for PropertySourcesPlaceholderConfigurer.
@Configuration
public class AppConfig {
@Bean
public static PropertySourcesPlaceholderConfigurer propertyPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
}
In the documentation:
> You may declare @Bean methods as static, allowing for them to be called without creating their containing configuration class as an instance. This makes particular sense when defining post-processor beans (for example, of type BeanFactoryPostProcessor or BeanPostProcessor), since such beans get initialized early in the container lifecycle and should avoid triggering other parts of the configuration at that point.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论