Spring boot 为什么不工作
我使用SpringBoot+jdbctemplate,并且我必须使用多数据源,例如Spring boot 为什么不工作,spring-boot,Spring Boot,我使用SpringBoot+jdbctemplate,并且我必须使用多数据源,例如 @配置 公共类MultiDBConfig{ @Bean(name=“fooDb”) @ConfigurationProperties(前缀=“foo.datasource”) 公共数据源fooDataSource(){ 返回DataSourceBuilder.create().build(); } @Bean(name=“fooJdbcTemplate”) 公共JdbcTemplate fooJdbcTempla
@配置
公共类MultiDBConfig{
@Bean(name=“fooDb”)
@ConfigurationProperties(前缀=“foo.datasource”)
公共数据源fooDataSource(){
返回DataSourceBuilder.create().build();
}
@Bean(name=“fooJdbcTemplate”)
公共JdbcTemplate fooJdbcTemplate(@Qualifier(“fooDb”)数据源ds){
返回新的JdbcTemplate(ds);
}
@Bean(name=“barDb”)
@ConfigurationProperties(前缀=“bar.datasource”)
公共数据源barDataSource(){
返回DataSourceBuilder.create().build();
}
@Bean(name=“barJdbcTemplate”)
公共JdbcTemplate barJdbcTemplate(@Qualifier(“barDb”)数据源ds){
返回新的JdbcTemplate(ds);
}
}
启动我的应用程序时,它失败,并有以下错误信息
Parameter 0 of method fooJdbcTemplate in com.example.multidatasourcedemo.MultiDBConfig required a single bean, but 3 were found:
- fooDb: defined by method 'fooDataSource' in class path resource [com/example/multidatasourcedemo/MultiDBConfig.class]
- barDb: defined by method 'barDataSource' in class path resource [com/example/multidatasourcedemo/MultiDBConfig.class]
- testDb: defined by method 'testDataSource' in class path resource [com/example/multidatasourcedemo/MultiDBConfig.class]
Action:
Consider marking one of the beans as @Primary, updating the consumer to accept multiple beans, or using @Qualifier to identify the bean that should be consumed
但是我显然使用了@限定符来标识bean,例如
@Bean(name=“fooJdbcTemplate”)
公共JdbcTemplate fooJdbcTemplate(@Qualifier(“fooDb”)数据源ds)
为什么@Qualifier
在这里不起作用?所以我做了一些调试,找到了一些可以解释发生了什么的东西。在这一点上,我不确定它是否是一个bug(可能是),但我也没有找到任何其他文档来澄清这一点
参考此为弹簧护套1.5.4
我从日志开始,您可以在下面找到一段摘录,更具体地说是关于DataSourceInitializer.init
(下面开头是==>
):
发生的情况是,在初始化数据源时,spring boot也会尝试初始化DB,该功能在默认情况下根据以下条件启用:
SpringJDBC有一个DataSource
initializer特性。Spring Boot默认启用它,并从标准位置schema.SQL
和data.SQL
(在类路径的根目录中)加载SQL
这发生在org.springframework.boot.autoconfigure.jdbc.DataSourceInitializer的@PostConstruct
部分:
@PostConstruct
公共void init(){
如果(!this.properties.isInitialize()){
debug(“已禁用初始化(未运行DDL脚本)”;
返回;
}
if(this.applicationContext.getBeanNamesForType(DataSource.class,false,false).length>0){
==>this.dataSource=this.applicationContext.getBean(dataSource.class);
}
if(this.dataSource==null){
debug(“未找到数据源,因此未初始化”);
返回;
}
runSchemaScripts();
}
如您所见,它尝试获取DataSource
以使用类this.DataSource=this.applicationContext.getBean(DataSource.class)执行DB初始化代码>并且由于有3个实例,并且没有主实例,因此按照
TgetBean(类requiredType)抛出BeanException
返回唯一匹配给定对象类型的bean实例(如果有)。
此方法进入ListableBeanFactory的按类型查找区域,但也可以根据给定类型的名称转换为传统的按名称查找。要跨多组bean执行更广泛的检索操作,请使用ListableBeanFactory和/或BeanFactoryUtils。
参数:
requiredType—bean必须匹配的类型;可以是接口或超类。不允许使用null。
返回:
与所需类型匹配的单个bean的实例
抛出:
NoSuchBeanDefinitionException-如果找不到给定类型的bean
==>如果找到给定类型的多个bean,则为NonuniqueBeandDefinitionException
BeansException-如果无法创建bean
所以,归根结底,在方法中自动连接@Qualifier(“fooDb”)
bean之前,就会发生这种情况,我相信您至少有这两种选择,在这两种情况下,您的@Qualifier
将在创建JdbcTemplate
时被考虑在内:
- 如果需要执行一些脚本来初始化数据库,则使用
@Primary
指示可以将哪个数据源
用于该任务
- 否则,您可以通过在
应用程序.properties
中添加spring.datasource.initialize=false来禁用此隐式功能(请参阅可配置的常用属性列表)
这可能是由几种不同的原因造成的。就我而言,我的情况如下:
- 在两个Java类中配置两个数据源Bean,但都给定了特定的Bean ID
- 数据源被注入的一个位置,但用限定符正确地进行了注释
- 正确排除DataSourceAutoConfiguration的SpringBoot应用程序
然而,这个bug被证明是:第二个类被注释为SpringBootApplication,它正在启动……在日志中丢失了。
所以,如果其他一切看起来都是正确的:检查是否有其他意外的SpringBootApplication正在启动。您能用
@Primary
注释标记三个*JdbcTemplate类并重试吗?通过这种方式,我们告诉Spring,当许多候选者都有资格使用autowire时,应该优先考虑。您使用的启动版本是什么,您可以共享一个来进行更多的调试吗?另外,您还可以(滚动到@Configuration Classes
)中的@Bean方法,例如:返回新的JdbcTemplate(fooDataSource())代码>@Morfic我使用了最新的1.5.4。我已经将这个小演示提交给github——你的应用在我的电脑上启动得很好。我没有一个数据库在本地运行,所以访问http://localhost:8080/?name=foo
在控件中添加@RequestParam(value=“name”)
后
org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'javax.sql.DataSource' available: expected single matching bean but found 3: fooDb,barDb,testDb
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveNamedBean(DefaultListableBeanFactory.java:1041) ~[spring-beans-4.3.9.RELEASE.jar:4.3.9.RELEASE]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:345) ~[spring-beans-4.3.9.RELEASE.jar:4.3.9.RELEASE]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:340) ~[spring-beans-4.3.9.RELEASE.jar:4.3.9.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1090) ~[spring-context-4.3.9.RELEASE.jar:4.3.9.RELEASE]
==> at org.springframework.boot.autoconfigure.jdbc.DataSourceInitializer.init(DataSourceInitializer.java:77) ~[spring-boot-autoconfigure-1.5.4.RELEASE.jar:1.5.4.RELEASE]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_45]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_45]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_45]
at java.lang.reflect.Method.invoke(Method.java:497) ~[na:1.8.0_45]
at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleElement.invoke(InitDestroyAnnotationBeanPostProcessor.java:366) ~[spring-beans-4.3.9.RELEASE.jar:4.3.9.RELEASE]
at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleMetadata.invokeInitMethods(InitDestroyAnnotationBeanPostProcessor.java:311) ~[spring-beans-4.3.9.RELEASE
...