使用AbstractRoutingDataSource并尝试设置多个DataSource时出现Spring引导错误

Mr.*_*Obb 5 java datasource spring-data spring-boot

我是Spring的新手,我正在开发一个新的应用程序,它需要能够连接到多个可用数据库中的一个.根据用户的凭据,我将确定要连接的数据库,因此我需要能够在运行时动态更改连接.我发现,概述了一个解决方案的不老泉博客这里是提倡使用AbstractRoutingDataSource的路由的getConnection()调用基于查找键之外的数据源.我试着仔细关注博客,但我一直收到以下错误.

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration': 
Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: 
Error creating bean with name 'dataSource' defined in robb.referencecomponent.Application: 
Invocation of init method failed; nested exception is org.springframework.jdbc.datasource.lookup.DataSourceLookupFailureException: 
Failed to look up JNDI DataSource with name 'dev1DataSource'; nested exception is javax.naming.NoInitialContextException: 
Need to specify class name in environment or system property, or as an applet parameter, or in an application resource file:  java.naming.factory.initial
Run Code Online (Sandbox Code Playgroud)

这是我的Application.java类的代码:

@SpringBootApplication
public class Application {

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

    @Bean
    @ConfigurationProperties(prefix="app.dev1.datasource")
    public DataSource dev1DataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean
    @ConfigurationProperties(prefix="app.dev2.datasource")
    public DataSource dev2DataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean
    public DataSource dataSource() {
        return new RoutingDataSource();
    }

    public class RoutingDataSource extends AbstractRoutingDataSource {
        public RoutingDataSource() {
            super();
            Map<Object, Object> targetDataSources = new HashMap<>();
            targetDataSources.put(DbLocation.DEV1, "dev1DataSource");
            targetDataSources.put(DbLocation.DEV2, "dev2DataSource");
            setTargetDataSources(targetDataSources);
            setDefaultTargetDataSource(DbLocation.DEV2);
        }

        @Override
        protected Object determineCurrentLookupKey() {
           return ClientContextHolder.getDbLocation();
        }
    }

}
Run Code Online (Sandbox Code Playgroud)

我在一个属性文件中设置DataSource配置,如下所示:

app.dev1.datasource.url=jdbc:oracle:thin:@dev1_db_url
app.dev1.datasource.username=dev1
app.dev1.datasource.password=XXXXXXX
app.dev1.datasource.driver-class-name=oracle.jdbc.OracleDriver

app.dev2.datasource.url=jdbc:oracle:thin:@dev2_db_url
app.dev2.datasource.username=dev2
app.dev2.datasource.password=XXXXXXX
app.dev2.datasource.driver-class-name=oracle.jdbc.OracleDriver
Run Code Online (Sandbox Code Playgroud)

我命名了我的一个DataSources'dev1DataSource',它抱怨它无法使用JNDI查找它,但是当我删除RoutingDataSource类和dataSource()bean定义并使dev1DataSource()bean @Primary我能够连接到dev1数据库很好.我不确定在将旧的博客代码移植到我的应用程序中我做错了什么,我知道使用xml在示例中设置bean但是我的设置了Java代码和注释,可能在那里犯了一些错误翻译?

有没有人有在Spring引导中使用AbstractRoutingDataSource的经验并且他们遇到过这种问题?

mp9*_*1de 3

AbstractRoutingDataSource支持多种查找机制。类型可能会有所不同,具体取决于默认为 JNDI 查找的value类型。这就是为什么你会看到初始化。targetDataSourcesDataSourceLookupNoInitialContextException

您有两种解决问题的选择:

  1. 提供已解析的DataSource实例而不是dev1DataSource/dev2DataSource字符串。您定义两个DataSource @Bean方法,并将其传递DataSourcesRoutingDataSource.
  2. 创建一个自己的DataSourceLookup,从 中获取配置属性Environment。自己DataSourceLookup必须负责缓存创建的实例和应用程序关闭,这就是我推荐选项 1 的原因。

  • 经过一番实验后,我将 `@Primary` 和 `@DependsOn({"dev1DataSource", "dev2DataSource"})` 添加到我的 `dataSource(DataSource dev1DataSource, DataSource dev2DataSource)` 方法中,该方法允许调用其他两个 DataSource 方法首先,多个 DataSource bean 不会出现任何错误。我还意识到我需要更改“RoutingDataSource()”内的“setDefaultTargetDataSource(DbLocation.DEV2);”方法调用以使用 DataSource 对象而不是枚举键。这些变化似乎已经让事情开始运转起来。谢谢。 (2认同)