首页 > 解决方案 > 在外部 Spring Boot 配置中定义任意数量的数据源

问题描述

我有一个提供不同类型数据的 Spring Boot Web 服务,其中每种类型都驻留在自己的数据库中。随着新类型的添加,我不想在代码中为每种类型配置数据源。这是我到目前为止所得到的:

数据类型及其数据库连接定义在application.yml

datatypes:
  someType:
    url: jdbc:postgresql://mydatabase.com:5432/some_type
    username: user1
    password: pass1
  otherType:
    url: jdbc:postgresql://mydatabase.com:5432/other_type
    username: user2
    password: pass2

配置类读取属性并创建DataSources 和JdbcTemplates:

@Configuration
@EnableConfigurationProperties
public class JdbcConfig {
  
  @Bean
  @ConfigurationProperties(prefix = "datatypes")
  public Map<String, DataSourceProperties> databaseConfig() {
    return new HashMap<>();
  }

  @Bean
  public Map<String, NamedParameterJdbcTemplate> jdbcTemplateMap() {
    Map<String, DataSourceProperties> databaseConfig = databaseConfig();

    Map<String, DataSource> dataSourceMap = databaseConfig().entrySet().stream()
        .collect(Collectors.toMap(Map.Entry::getKey, entry -> 
            entry.getValue().initializeDataSourceBuilder().build()));

    return dataSourceMap.entrySet().stream()
        .collect(Collectors.toMap(Map.Entry::getKey, entry ->
            new NamedParameterJdbcTemplate(entry.getValue())));
  }
}

最后是一个根据其类型获取数据的存储库:

@Repository
public class MyRepository {
  @Autowired
  private Map<String, NamedParameterJdbcTemplate> jdbcTemplateMap;

  public Item getItem(String dataType, String id) {
    String sql = "select * from item where id = :id";
    return jdbcTemplateMap.get(dataType)
               .queryForObject(sql, Map.of("id", id), new ItemRowMapper());
  }
}

当 Spring 尝试jdbcTemplateMap在存储库中自动装配时,它找不到任何 jdbc 模板 bean,因此自动配置启动但失败,因为数据源的属性不在 yml 中的预期位置。这可以通过禁用自动配置来解决:@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)

这个设置几乎可以工作。但是,由于DataSource实例未在应用程序上下文中注册,因此我错过了其他一些自动配置魔法,例如执行器健康检查。我尝试自己注册它们,方法是将其添加到bean 方法并从该方法JdbcConfig调用:registerDataSource()jdbcTemplateMap()

@Autowired
private ApplicationContext applicationContext;

private void registerDataSource(String beanName, DataSource dataSource) {
  ConfigurableApplicationContext context = 
      (ConfigurableApplicationContext) applicationContext;
  ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
  beanFactory.registerSingleton(beanName, dataSource);
}

有了这个,我应该能够再次启用数据源自动配置,但它在jdbcTemplateMap()有机会运行之前运行。执行器也不会拾取它们。这可以解决吗?

标签: javaspringspring-boot

解决方案


推荐阅读