如何在不读取application.properties的情况下以编程方式初始化辅助/其他数据源

时间:2017-04-01 07:27:22

标签: java spring hibernate spring-boot multi-tenant

我开发了一个多租户spring引导应用程序,其中数据源通过存储在application.properties中的数据库凭证进行初始化,如下所示:

application.properties

spring.multitenancy.datasource1.url=jdbc:mysql://localhost:3306/db1
spring.multitenancy.datasource1.username=root
spring.multitenancy.datasource1.password=****
spring.multitenancy.datasource1.driver-class-name=com.mysql.jdbc.Driver
spring.jpa.hibernate.ddl-auto=update

spring.multitenancy.datasource2.url=jdbc:mysql://localhost:3306/db2
spring.multitenancy.datasource2.username=root
spring.multitenancy.datasource2.password=****
spring.multitenancy.datasource2.driver-class-name=com.mysql.jdbc.Driver
spring.jpa.hibernate.ddl-auto=update

spring.multitenancy.datasource3.url=jdbc:mysql://localhost:3306/db3
spring.multitenancy.datasource3.username=root
spring.multitenancy.datasource3.password=****
spring.multitenancy.datasource3.driver-class-name=com.mysql.jdbc.Driver
spring.jpa.hibernate.ddl-auto=update

DataSourceConfig.java

@Configuration
public class DataSourceConfig {

    @Autowired
    private MultitenancyProperties multitenancyProperties;

    @Bean(name = { "dataSource", "dataSource1" })
    @ConfigurationProperties(prefix = "spring.multitenancy.datasource1")
    public DataSource dataSource1() {
        DataSourceBuilder factory = DataSourceBuilder
                .create(this.multitenancyProperties.getDatasource1().getClassLoader())
                .driverClassName(this.multitenancyProperties.getDatasource1().getDriverClassName())
                .username(this.multitenancyProperties.getDatasource1().getUsername())
                .password(this.multitenancyProperties.getDatasource1().getPassword())
                .url(this.multitenancyProperties.getDatasource1().getUrl());
        return factory.build();
    }

    @Bean(name = "dataSource2")
    @ConfigurationProperties(prefix = "spring.multitenancy.datasource2")
    public DataSource dataSource2() {
        DataSourceBuilder factory = DataSourceBuilder
                .create(this.multitenancyProperties.getDatasource2().getClassLoader())
                .driverClassName(this.multitenancyProperties.getDatasource2().getDriverClassName())
                .username(this.multitenancyProperties.getDatasource2().getUsername())
                .password(this.multitenancyProperties.getDatasource2().getPassword())
                .url(this.multitenancyProperties.getDatasource2().getUrl());
        return factory.build();
    }

    @Bean(name = "dataSource3")
    @ConfigurationProperties(prefix = "spring.multitenancy.datasource3")
    public DataSource dataSource3() {
        DataSourceBuilder factory = DataSourceBuilder
                .create(this.multitenancyProperties.getDatasource3().getClassLoader())
                .driverClassName(this.multitenancyProperties.getDatasource3().getDriverClassName())
                .username(this.multitenancyProperties.getDatasource3().getUsername())
                .password(this.multitenancyProperties.getDatasource3().getPassword())
                .url(this.multitenancyProperties.getDatasource3().getUrl());
        return factory.build();
    }
}

此处,数据源通过存储在应用程序属性中的值进行初始化。

MultitenancyProperties.java

@ConfigurationProperties("spring.multitenancy")
public class MultitenancyProperties {

    @NestedConfigurationProperty
    private DataSourceProperties datasource1;

    @NestedConfigurationProperty
    private DataSourceProperties datasource2;

    @NestedConfigurationProperty
    private DataSourceProperties datasource3;

    public DataSourceProperties getDatasource1() {
        return datasource1;
    }

    public void setDatasource1(DataSourceProperties datasource1) {
        this.datasource1 = datasource1;
    }

    public DataSourceProperties getDatasource2() {
        return datasource2;
    }

    public void setDatasource2(DataSourceProperties datasource2) {
        this.datasource2 = datasource2;
    }

    public DataSourceProperties getDatasource3() {
        return datasource3;
    }

    public void setDatasource3(DataSourceProperties datasource3) {
        this.datasource3 = datasource3;
    }
}

Spring启动应用程序启动器

@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
@EnableConfigurationProperties(MultitenancyProperties.class)
public class Application {

    public static void main(String[] args) {
        ApplicationContext ctx = SpringApplication.run(Application.class, args);
    }
}

如何通过读取存储在主数据源表中的数据库凭证以编程方式读取application.properties和其他数据源(dataSource2,dataSource3)来初始化主数据源。

4 个答案:

答案 0 :(得分:2)

假设您的名称为DATABASECONFIG的primay数据源中有一个数据库,并且具有以下架构:

+-----------+-----------+-----------+-----------+-----------+
|                         DATABASECONFIG                    |
+-----------+-----------+-----------+-----------+-----------+
| DB_NAME   |     URL   |  USERNAME | PASSWORD  |  DRIVER   |
+-----------+-----------+-----------+-----------+-----------+

您可以将DataSourceConfig课改为:

@Configuration
public class DataSourceConfig {

    @Autowired
    private MultitenancyProperties multitenancyProperties;

    @Bean(name = { "dataSource", "dataSource1" })
    @ConfigurationProperties(prefix = "spring.multitenancy.datasource1")
    public DataSource dataSource1() throws SQLException {
        ClassLoader classLoader = this.multitenancyProperties.getDatasource1().getClassLoader();
        DataSourceBuilder factory = DataSourceBuilder
                .create(this.multitenancyProperties.getDatasource1().getClassLoader())
                .driverClassName(this.multitenancyProperties.getDatasource1().getDriverClassName())
                .username(this.multitenancyProperties.getDatasource1().getUsername())
                .password(this.multitenancyProperties.getDatasource1().getPassword())
                .url(this.multitenancyProperties.getDatasource1().getUrl());
        return factory.build();
    }

    @Bean(name = "dataSource2")
    @ConfigurationProperties(prefix = "spring.multitenancy.datasource2")
    public DataSource dataSource2()
            throws Exception {
        String dataSourceName = "datasource2";
        return this.getSecondaryDataSource(dataSourceName);
    }

    @Bean(name = "dataSource3")
    @ConfigurationProperties(prefix = "spring.multitenancy.datasource3")
    public DataSource dataSource3()
            throws Exception {
        String dataSourceName = "datasource3";
        return this.getSecondaryDataSource(dataSourceName);
    }

    private DataSource getSecondaryDataSource(String dataSourceName)
            throws Exception {
        DataSource d = this.dataSource1();
        PreparedStatement preparedStatement = d.getConnection().prepareStatement("SELECT * FROM DATABASECONFIG WHERE DB_NAME = ?");
        preparedStatement.setString(1, dataSourceName);
        ResultSet resultSet = preparedStatement.executeQuery();
        if (!resultSet.next()) {
            // No result found --> throw exception
            throw new Exception("Error Finding DB Config for DataSource [" + dataSourceName + "].");
        }
        DataSourceBuilder factory = DataSourceBuilder
                .create()
                .driverClassName(resultSet.getString("DRIVER"))
                .username(resultSet.getString("USERNAME"))
                .password(resultSet.getString("PASSWORD"))
                .url(resultSet.getString("URL"));
        return factory.build();
    }
}

答案 1 :(得分:0)

我会做以下事情:

属性文件

spring.multitenancy.datasource1.url=jdbc:mysql://localhost:3306/db1
spring.multitenancy.datasource1.username=root
spring.multitenancy.datasource1.password=****
spring.multitenancy.datasource1.driver-class-name=com.mysql.jdbc.Driver
spring.jpa.hibernate.ddl-auto=update

Spring配置

@Configuration
public class DataSourceConfig {

    @ConfigurationProperties(prefix = "spring.multitenancy.datasource1")
    private DataSourceProperties ds;

    @Bean
    public DataSource dataSource1() {
        DataSourceBuilder factory = DataSourceBuilder
                .create(ds.getClassLoader())
                .driverClassName(ds.getDriverClassName())
                .username(ds.getUsername())
                .password(ds.getPassword())
                .url(ds.getUrl());
        return factory.build();
    }
    @Bean
    public DataSource dataSource2() {
        createFromDataSource1Conf("key2");
    }

    @Bean
    public DataSource dataSource3() {
        createFromDataSource1Conf("key3");
    }

    private DataSource createFromDataSource1Conf(Object configPrefix) {
        // Query db and create datasources
    }

}

我不太确定以这种方式使用@ConfigurationProperties会起作用,但你可以像现在一样使用它。

@ConfigurationProperties(prefix = "spring.multitenancy.datasource1")
private DataSourceProperties ds;

答案 2 :(得分:0)

将您的@Configuration类分成两部分。首先在autowire it into the second中创建主数据源;使其可用于从属数据源@Bean方法。

答案 3 :(得分:-1)

首先你可以导入commons-dbcp2.jar,然后你可以创建一个org.apache.commons.dbcp.BasicDataSource,例如,

 BasicDataSource ds = new BasicDataSource();
    ds.setDriverClassName("com.mysql.jdbc.Driver");
    ds.setUrl("jdbc:mysql://localhost:3306/housesearch");
    ds.setUsername("root");
    ds.setPassword("");
    ds.setInitialSize(50);
    ds.setMaxIdle(30);
    Connection connection = ds.getConnection();
    Statement statement = connection.createStatement();
    ResultSet resultSet = statement.executeQuery("select * from pay_info");
    if(resultSet.next()){
        System.out.println(resultSet.getInt(5));
    }
    connection.close();
    ds.close();

driverClassName,url,password和其他属性可以存储在表中。

我希望我的回答可以帮到你。