在Spring Boot中获取当前活动的数据源的引用

28

我希望通过DataSourceInitializer实现数据库数据初始化。

我在Spring Boot主方法下面有这些方法,但似乎没有被执行(我试着故意删除字符以引发错误来确认执行情况,但什么也没发生):

@ConfigurationProperties(prefix="spring.datasource")
@Bean
public DataSource getDataSource() {

    // i was hoping this was going to pull my current datasource, as 
    // defined in application.properties
    return DataSourceBuilder
            .create()
            .build();
}


@Bean
public DataSourceInitializer dataSourceInitializer() {
    ResourceDatabasePopulator resourceDatabasePopulator = new ResourceDatabasePopulator();
    resourceDatabasePopulator.addScript(new ClassPathResource("/data/init/initData.sql"));

    DataSourceInitializer dataSourceInitializer = new DataSourceInitializer();

    // the call to the above method
    dataSourceInitializer.setDataSource(getDataSource());


    dataSourceInitializer.setDatabasePopulator(resourceDatabasePopulator);

    return dataSourceInitializer;
}

更新:这个问题是为了获取正在使用的dataSource的引用。以下问题解释了如何以非常简单的方式初始化数据: DataSourceInitializer is not working on Spring boot 1.2

2个回答

56
如果您已经创建了数据源,它将在Spring容器中,所以:
@Autowired
DataSource dataSource;

应该这样做。


我已经做了更改,但数据库中仍然没有变化。你知道我的代码还可能有什么问题吗? - developer10
6
Java魔法!谢谢这个。在我的情况下,我有多个可能的自动装配选择,所以不得不指定一个更加细粒度的数据源类,如下所示:@Autowired private HikariDataSource dataSource; - Shanerk
如果您有不同的数据源怎么办? - itro
@itro,你可以自动装配 Spring 容器中的任何接口或类,如果有唯一匹配项,它将被找到。 - Essex Boy

0
你说你的应用程序主方法下有以下方法,而且你没有使用自动装配数据源,所以你直接创建了一个实例,因此没有使用属性。你需要使用Spring创建的单例对象。为了做到这一点,你有两种可能性:
第一种选择,也是你应该使用的选择,就是声明一个配置类来创建你的bean:
@Configuration
public class DatasourceConfig
{

    @ConfigurationProperties(prefix="spring.datasource")
    @Bean
    public DataSource getDataSource() {

        // i was hoping this was going to pull my current datasource, as 
        // defined in application.properties
        return DataSourceBuilder
                .create()
                .build();
    }

    @Bean
    public DataSourceInitializer dataSourceInitializer() {
        ResourceDatabasePopulator resourceDatabasePopulator = new ResourceDatabasePopulator();
        resourceDatabasePopulator.addScript(new ClassPathResource("/data/init/initData.sql"));

        DataSourceInitializer dataSourceInitializer = new DataSourceInitializer();

        // the call to the above method
        dataSourceInitializer.setDataSource(getDataSource());


        dataSourceInitializer.setDatabasePopulator(resourceDatabasePopulator);

        return dataSourceInitializer;
    }

}

使用@Configuration,即使直接调用方法,由于配置类在启动时会被CGLIB子类化,因此您将获得由Spring创建的对象。

有关Java基于配置如何在内部工作的更多信息

第二个选项是在第二个方法中自动装配数据源:

@Bean
@Autowired
public DataSourceInitializer dataSourceInitializer(DataSource myDatasource) {
    ResourceDatabasePopulator resourceDatabasePopulator = new ResourceDatabasePopulator();
    resourceDatabasePopulator.addScript(new ClassPathResource("/data/init/initData.sql"));

    DataSourceInitializer dataSourceInitializer = new DataSourceInitializer();

    dataSourceInitializer.setDataSource(myDatasource);
    dataSourceInitializer.setDatabasePopulator(resourceDatabasePopulator);

    return dataSourceInitializer;
}

请看我问题末尾的更新。它确实可以这样工作,但是肯定有很多魔法,我希望学习如何摆脱Boot的自动配置。 现在,我尝试了将DataSource作为字段进行@Autowired,以及按照您建议的方式,在@Bean下面放置它。两种方法都没有起作用。 - developer10
@developer10,你的bean是否使用属性正确初始化了?DataSourceInitializer是否被创建了?如果没有,能否请你展示一下你的主方法? - alfcope
我的主方法是标准的SpringBoot方法,只有标准行。我不知道如何检查您所要求的内容 - 我没有看到任何错误提示它不是。但是,我怀疑它根本没有被调用。这可能吗? 注意:此时我对默认行为感到满意 - Spring Boot拉取并执行我放在资源根目录中的data.sql文件(因为没有其他必要的操作 - 我只是暂时注释了相关方法)。 - developer10
1
只需在您的 @Bean 方法中记录一些内容。同时,在启动应用程序时,请检查bean是否被覆盖。查找类似于“Overriding bean definition for bean 'dataSourceInitializer'”的内容。 - alfcope

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接