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

如何在Spring Boot中触发接口后再创建数据源而非启动时?

动态创建并缓存HikariDataSource实现方案(Spring Boot + JPA)

你的需求核心是延迟初始化数据源,不在启动阶段绑定配置,而是在首次请求时根据请求头动态获取数据库信息、创建数据源并缓存复用。以下是具体实现步骤:

1. 禁用Spring Boot自动数据源配置

首先阻止Spring Boot启动时强制加载数据源配置,在启动类上排除相关自动配置类:

@SpringBootApplication(exclude = {
    DataSourceAutoConfiguration.class,
    HibernateJpaAutoConfiguration.class,
    DataSourceTransactionManagerAutoConfiguration.class
})
public class DynamicDatasourceApplication {
    public static void main(String[] args) {
        SpringApplication.run(DynamicDatasourceApplication.class, args);
    }
}

2. 实现数据源缓存管理器

创建单例组件,负责缓存已创建的数据源,确保同一请求标识(比如请求头中的X-DB-Key)复用同一个数据源:

@Component
public class DataSourceCache {
    private final ConcurrentHashMap<String, HikariDataSource> dataSourceCache = new ConcurrentHashMap<>();
    // 注入获取数据库配置的服务(需自行实现,根据请求头调用外部接口拿配置)
    private final DatabaseConfigService configService;

    public DataSourceCache(DatabaseConfigService configService) {
        this.configService = configService;
    }

    public HikariDataSource getDataSource(String dbKey) {
        // 不存在则创建并缓存,线程安全
        return dataSourceCache.computeIfAbsent(dbKey, this::createDataSource);
    }

    private HikariDataSource createDataSource(String dbKey) {
        // 调用服务获取数据库配置
        DatabaseConfig dbConfig = configService.fetchDbConfig(dbKey);
        
        HikariDataSource dataSource = new HikariDataSource();
        dataSource.setJdbcUrl(dbConfig.getJdbcUrl());
        dataSource.setUsername(dbConfig.getUsername());
        dataSource.setPassword(dbConfig.getPassword());
        dataSource.setDriverClassName("org.postgresql.Driver");
        dataSource.setMaximumPoolSize(10);
        dataSource.setMinimumIdle(2);
        return dataSource;
    }

    // 应用关闭时清理数据源,避免资源泄漏
    @PreDestroy
    public void cleanUp() {
        dataSourceCache.values().forEach(HikariDataSource::close);
    }
}

3. 动态创建EntityManagerFactory(适配JPA)

因为Spring Data JPA默认依赖启动时的EntityManagerFactory,所以需要动态创建对应数据源的实例并缓存:

@Component
public class EntityManagerFactoryProvider {
    private final ConcurrentHashMap<String, EntityManagerFactory> emfCache = new ConcurrentHashMap<>();
    private final DataSourceCache dataSourceCache;
    private final EntityManagerFactoryBuilder emfBuilder;

    public EntityManagerFactoryProvider(DataSourceCache dataSourceCache, EntityManagerFactoryBuilder emfBuilder) {
        this.dataSourceCache = dataSourceCache;
        this.emfBuilder = emfBuilder;
    }

    public EntityManagerFactory getEntityManagerFactory(String dbKey) {
        return emfCache.computeIfAbsent(dbKey, key -> {
            HikariDataSource dataSource = dataSourceCache.getDataSource(key);
            return emfBuilder.dataSource(dataSource)
                    .packages("com.yourproject.entity") // 替换为你的实体类包路径
                    .persistenceUnit(key) // 每个数据源对应独立的持久化单元
                    .build();
        });
    }

    @PreDestroy
    public void cleanUp() {
        emfCache.values().forEach(EntityManagerFactory::close);
    }
}

4. 控制器中动态使用数据源

在接口方法中,通过请求头获取标识,拿到对应的EntityManagerFactory执行数据库操作:

@RestController
@RequestMapping("/demo")
public class DemoController {
    private final EntityManagerFactoryProvider emfProvider;

    public DemoController(EntityManagerFactoryProvider emfProvider) {
        this.emfProvider = emfProvider;
    }

    @GetMapping("/list")
    public List<DemoEntity> getDemoList(@RequestHeader("X-DB-Key") String dbKey) {
        EntityManagerFactory emf = emfProvider.getEntityManagerFactory(dbKey);
        // 每次请求创建EntityManager,用完自动关闭
        try (EntityManager em = emf.createEntityManager()) {
            return em.createQuery("SELECT e FROM DemoEntity e", DemoEntity.class)
                    .getResultList();
        }
    }
}

额外注意事项

  • 事务支持:如果需要事务,可创建PlatformTransactionManager缓存并绑定对应数据源,手动管理事务或通过AOP动态切换事务管理器。
  • Spring Data JPA Repository适配:若想继续使用Spring Data的Repository接口,需自定义Repository工厂,根据当前请求的数据源动态生成代理实例,可参考RepositoryFactorySupport实现。
  • 资源清理:务必在应用关闭时调用数据源和EntityManagerFactory的close方法,避免连接池泄漏。

内容的提问来源于stack exchange,提问作者Praveen Kumar

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 16:56:11