Spring boot 为什么不工作

Spring boot 为什么不工作,spring-boot,Spring Boot,我使用SpringBoot+jdbctemplate,并且我必须使用多数据源,例如 @配置 公共类MultiDBConfig{ @Bean(name=“fooDb”) @ConfigurationProperties(前缀=“foo.datasource”) 公共数据源fooDataSource(){ 返回DataSourceBuilder.create().build(); } @Bean(name=“fooJdbcTemplate”) 公共JdbcTemplate fooJdbcTempla

我使用SpringBoot+jdbctemplate,并且我必须使用多数据源,例如

@配置
公共类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
    ...