java - 如何在 Spring Boot 运行时添加新的数据源

标签 java spring spring-boot spring-data-jpa spring-data

我有这个,但我没有找到任何可能的解决方案。我找到的所有答案都是关于配置两个或多个数据源或 Multi-Tenancy 数据库,但这不是我需要的。
我必须这样做:

  1. 从 application.properties 配置第一个数据源。这是主要的数据库配置
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
        entityManagerFactoryRef = "primaryEntityManagerFactory",
        basePackages = "com.example.primary")
public class SmartConnectConfig {

    @Primary
    @Bean(name = "primaryDatasource")
    @ConfigurationProperties(prefix = "spring.datasource")
    public DataSource dataSource() {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setUrl(env.getProperty("spring.datasource.url"));
        dataSource.setUsername(env.getProperty("spring.datasource.username"));
        dataSource.setPassword(env.getProperty("spring.datasource.password"));
        return dataSource;
    }

    @Primary
    @Bean(name = "primaryEntityManagerFactory")
    public LocalContainerEntityManagerFactoryBean entityManagerFactory(
            EntityManagerFactoryBuilder builder,
            @Qualifier("primaryDatasource") DataSource dataSource) {
        return builder
                .dataSource(dataSource)
                .packages("com.example.primary")
                .persistenceUnit("primary")
                .build();
    }

    @Primary
    @Bean(name = "transactionManager")
    public PlatformTransactionManager transactionManager(
            @Qualifier("primaryEntityManagerFactory") EntityManagerFactory entityManagerFactory) {
        return new JpaTransactionManager(entityManagerFactory);
    }
  • 当用户根据组织连接到系统时,进行查询,获取第一个数据库中保存的所有属性或组织数据库,以获取第二个数据源的配置(url、用户名、密码、driverClassName)。这是非常重要,因为根据用户登录,我需要根据组织创建不同的数据源。
  • 添加到 spring 以使用第二个数据源管理某些存储库
    注意:第一个和第二个存储库位于不同的包中,因为 Spring 可以扫描这些存储库,第二个包是“com.example.second”。
  • 有人可以给一些建议。
    谢谢

    最佳答案

    有大量资源解释了如何使用各种选项和各种方式在 Spring Boot 中配置数据源来检索连接的配置详细信息(从外部文件、application.properties、硬编码等)。 另一方面,如果您已经配置了数据源,并且在运行时想要更改此连接的详细信息(可能是数据库的主机名更改)而不重新启动应用程序,则该信息有点稀缺。

    我所说的用例是允许用户更改数据库的全部或部分连接详细信息(例如主机名)的情况。 用户有一个“设置”页面,可以在其中编辑这些详细信息。此设置保存在外部文件中,而不是 application.properties 中。 在这种情况下,对于对该数据库的后续请求,需要使用新参数。 Spring的默认行为是将Bean创建为Singleton,包括您配置的DataSource,因此,如果您更改设置,则不会重新创建Bean(它仍将使用旧参数)。

    在这里,我介绍了如何实现这一目标的多种方法之一。

    创建数据源

    有多种方法可以创建在 Spring Boot 中使用的数据源,并且为此提供了大量资源。 在这里,我展示了如何创建一个在单独的包中配置的简单的基于 JdbcTemplate 的存储库(不会使用 application.properties 中定义的数据库属性)。

    这是数据源的配置片段:

    @Configuration
    public class CustomDataSourceConfiguration {
    
        @Lazy
        @Bean
        @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
        public DataSource customDataSource() {
            DataSourceBuilder dsBuilder = DataSourceBuilder.create();
            dsBuilder.driverClassName(„oracle.jdbc.driver.OracleDriver“);
            CustomDatabaseSettings dbSettings = <….>//Here obtain the settings from whereever you need
            dsBuilder.url(dbSettings.jdbcUrl());
            dsBuilder.username(dbSettings.username());
            dsBuilder.password(dbSettings.password());
            return dsBuilder.build();
        }
    
        @Lazy
        @Qualifier(„customJdbcTemplate“)
        @Bean
        public JdbcTemplate customJdbcTemplate() {
            return new JdbcTemplate(customDataSource());
        }
    
    }
    

    在这里,我使用一个注释为 Configuration 类的类来定义 DataSource 和 JdbcTemplate 所需的 Bean。 @Lazy 注释在这种情况下很重要,因为我从 Java 代码中读取了保存数据库配置的外部文件,并且这种情况发生在 Spring 容器初始化所有 bean 之后。 默认情况下,Beans是Eagerly加载的,这意味着当Spring扫描它们并遇到它们时,它将实例化它们。 Lazy 将等待初始化,直到发出对该 bean 的第一个请求。 请参阅 @Lazy 的文档 – https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/context/annotation/Lazy.html

    bean 的范围设置为“Prototype”。默认情况下,范围设置为 Singleton,但正如我在文章开头所说,我们需要一种方法来使用新的配置详细信息重新初始化数据源,最简单的方法是使用此范围。每次请求 bean 时,此范围都会调用初始化。 从代码中可以看出,这非常适合我们的情况,因为再次调用初始化方法也将获取新配置的数据库连接详细信息。 使用 Prototype 有一些注意事项。 有关范围的更多信息可以在文档中找到:https://docs.spring.io/spring/docs/3.0.0.M3/reference/html/ch04s04.html

    这也是存储库的代码:

    @Lazy
    @Repository
    @ComponentScan(basePackages = „com.cli.jdbc.datasource“)
    public class CustomRepository{
    
        @Qualifier(„customJdbcTemplate“)
        @Autowired
        private JdbcTemplate jdbcTemplate;
    
    //Implement methods here
    

    因此,我们通过读取在运行时动态更改的自定义配置文件来配置数据源。 现在,当设置更改时,我们需要一种方法来重新初始化数据源。 从概念上讲,这是通过简单地从 Spring Context 中检索 DataSource bean 来完成的。因为我们使用了 Prototype 作用域,这将导致上面定义的方法中的逻辑被再次调用,这反过来又会对我们的数据库进行最新的更改。在此步骤之后,我们还需要从上下文中检索 jdbcTemplate 并将这个新的 DataSource 设置给它。

    代码如下所示:

    public void refreshCustomJdbc() {
            DataSource ds = (DataSource) getSpringContext().getBean(„customDataSource“);
            JdbcTemplate customJdbcTemplate = (JdbcTemplate) getSpringContext().getBean(„customJdbcTemplate“);
            customJdbcTemplate.setDataSource(ds);
        }
    

    引用: https://blog.virtual7.de/dynamically-change-data-source-connection-details-at-runtime-in-spring-boot/

    关于java - 如何在 Spring Boot 运行时添加新的数据源,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54578227/

    相关文章:

    Spring:不同ApplicationContext的不同日志记录行为

    java - 在多个资源请求的情况下恢复更改的最佳做法是什么?

    java - 多模块 spring boot 项目 messages.properties 未加载

    spring-boot - Spring-Boot 配置 : How to keep whitespace in yaml key being used to populate Map<String, 字符串>

    java - 用于分割给定数据的 Elasticsearch 分词器与过滤器

    java - 不使用 HttpServlerRequest 获取 HttpSession 对象的不同方法

    java - PDFBox - 仅复制页面资源而不是复制文档的所有资源

    javax.management.InstanceNotFoundException

    java - Spring 批处理 : Not all threads are running from the threadpool

    spring-boot - 无论 CascadeTypes 如何,都无法在不删除父实体的情况下删除子实体?