Spring 使用 AbstractRoutingDataSource 并尝试设置多个数据源时出现启动错误
Spring boot error when using AbstractRoutingDataSource and trying to set up multiple DataSources
我是 Spring 引导的新手,我正在开发一个需要能够连接到多个可用数据库之一的新应用程序。根据用户的凭据,我将确定要连接到哪个数据库,因此我需要能够在运行时动态更改连接。我找到了一篇旧的 Spring 博客,其中概述了针对此 here 的解决方案,该博客提倡使用 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
这是我的 Application.java class:
的代码
@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();
}
}
}
然后我在属性文件中设置数据源配置,如下所示:
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
我将我的一个数据源命名为 'dev1DataSource',它抱怨说它无法使用 JNDI 查找它,但是当我删除 RoutingDataSource class 和 dataSource() bean 定义并使dev1DataSource() bean @Primary 我能够很好地连接到 dev1 数据库。我不确定我在将旧博客的代码移植到我的应用程序时做错了什么,我知道示例中的 bean 是使用 xml 设置的,但我的设置是使用 Java 代码和注释, 也许是那个翻译有一些错误?
有没有人有在 Spring 启动时使用 AbstractRoutingDataSource 的经验,他们是否遇到过此类问题?
AbstractRoutingDataSource
支持多种查找机制。 targetDataSources
的 value
类型可能会有所不同,具体取决于默认为 JNDI 查找的 DataSourceLookup
。这就是为什么您在初始化时看到 NoInitialContextException
。
您有两种解决问题的方法:
- 提供已解决的
DataSource
个实例,而不是 dev1DataSource
/dev2DataSource
个字符串。您定义了两个 DataSource
@Bean
方法,并将 DataSources
传递给 RoutingDataSource
. 的初始化
- 创建一个自己的
DataSourceLookup
,从 Environment
中获取配置属性。自己的 DataSourceLookup
必须负责缓存创建的实例和关闭应用程序,这就是我推荐选项 1 的原因。
我是 Spring 引导的新手,我正在开发一个需要能够连接到多个可用数据库之一的新应用程序。根据用户的凭据,我将确定要连接到哪个数据库,因此我需要能够在运行时动态更改连接。我找到了一篇旧的 Spring 博客,其中概述了针对此 here 的解决方案,该博客提倡使用 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
这是我的 Application.java class:
的代码@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();
}
}
}
然后我在属性文件中设置数据源配置,如下所示:
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
我将我的一个数据源命名为 'dev1DataSource',它抱怨说它无法使用 JNDI 查找它,但是当我删除 RoutingDataSource class 和 dataSource() bean 定义并使dev1DataSource() bean @Primary 我能够很好地连接到 dev1 数据库。我不确定我在将旧博客的代码移植到我的应用程序时做错了什么,我知道示例中的 bean 是使用 xml 设置的,但我的设置是使用 Java 代码和注释, 也许是那个翻译有一些错误?
有没有人有在 Spring 启动时使用 AbstractRoutingDataSource 的经验,他们是否遇到过此类问题?
AbstractRoutingDataSource
支持多种查找机制。 targetDataSources
的 value
类型可能会有所不同,具体取决于默认为 JNDI 查找的 DataSourceLookup
。这就是为什么您在初始化时看到 NoInitialContextException
。
您有两种解决问题的方法:
- 提供已解决的
DataSource
个实例,而不是dev1DataSource
/dev2DataSource
个字符串。您定义了两个DataSource
@Bean
方法,并将DataSources
传递给RoutingDataSource
. 的初始化
- 创建一个自己的
DataSourceLookup
,从Environment
中获取配置属性。自己的DataSourceLookup
必须负责缓存创建的实例和关闭应用程序,这就是我推荐选项 1 的原因。