Java 具有多个JdbcTemplate和Spring引导的NoSuchBeanDefinitionException

Java 具有多个JdbcTemplate和Spring引导的NoSuchBeanDefinitionException,java,spring,spring-boot,spring-jdbc,Java,Spring,Spring Boot,Spring Jdbc,我正在使用SpringBootStarter jdbc并尝试使用多个jdbc数据源,当我为JdbcTemplate使用命名bean,然后使用@Qualifier将正确的JdbcTemplate注入我的存储库时,一切都正常 应用程序: 打包my.app; @SpringBoot应用程序 @启用自动配置 公共类应用程序实现CommandLineRunner{ @自动连线 私有MyRepository存储库; 公共静态void main(字符串[]args){ SpringApplication.ru

我正在使用SpringBootStarter jdbc并尝试使用多个jdbc数据源,当我为JdbcTemplate使用命名bean,然后使用@Qualifier将正确的JdbcTemplate注入我的存储库时,一切都正常

应用程序:

打包my.app;
@SpringBoot应用程序
@启用自动配置
公共类应用程序实现CommandLineRunner{
@自动连线
私有MyRepository存储库;
公共静态void main(字符串[]args){
SpringApplication.run(Application.class,args);
}
@凌驾
公共无效运行(字符串…参数)引发异常{
List stuff=repository.getStuff();
}
}
配置:

打包my.app;
@配置
@组件扫描
公共类AppConfig{
@Bean(name=“datasource1”)
@ConfigurationProperties(前缀=“db1.datasource”)
公共数据源数据源1(){
返回DataSourceBuilder.create().build();
}
@Bean(name=“db1”)
公共数据源db1(@Qualifier(“datasource1”数据源ds){
返回新的JdbcTemplate(ds);
}
@Bean(name=“datasource2”)
@ConfigurationProperties(前缀=“db2.datasource”)
公共数据源数据源2(){
返回DataSourceBuilder.create().build();
}
@Bean(name=“db2”)
公共数据源db1(@Qualifier(“datasource1”数据源ds){
返回新的JdbcTemplate(ds);
}
}
存储库:

打包my.app;
@存储库
公共类MyRepository{
私有jdbc模板db1;
私有jdbc模板db2;
@自动连线
公共类MyRepository(@Qualifier(“db1”)JdbcTemplate db1,@Qualifier(“db2”)JdbcTemplate db2){
this.db1=db1;
this.db2=db2;
}
}
当我实例化MyRepository时,一切都很好

我进行了一些重构,试图为Db2JdbcTemplate和Db2JdbcTemplate创建新的类,以便可以在不使用限定符的情况下插入它们。不幸的是,当我这样做时,会出现以下异常:

以下是我试图做的:

已从AppConfig中删除命名的JdbcTemplate bean:

打包my.app;
@配置
@组件扫描
公共类AppConfig{
@Bean(name=“datasource1”)
@ConfigurationProperties(前缀=“db1.datasource”)
公共数据源数据源1(){
返回DataSourceBuilder.create().build();
}
@Bean(name=“datasource2”)
@ConfigurationProperties(前缀=“db2.datasource”)
公共数据源数据源2(){
返回DataSourceBuilder.create().build();
}
}
为命名的JdbcTemplates创建了2个新类:

打包my.app;
@组成部分
公共类Db1JdbcTemplate扩展了JdbcTemplate{
@自动连线
公共Db1JdbcTemplate(@Qualifier(“datasource1”)数据源ds1){
超级(ds1);
}
} 
打包my.app;
@组成部分
公共类Db2JdbcTemplate扩展了JdbcTemplate{
@自动连线
公共Db2JdbcTemplate(@Qualifier(“datasource2”)数据源ds2){
超级(ds2);
}
} 
修改MyRepository以使用以下内容:

package my.app;

@Repository
public class MyRepository {
  private Db1JdbcTemplate db1;
  private Db2JdbcTemplate db2;

  @Autowired
  public class MyRepository(Db1JdbcTemplate db1, Db2JdbcTemplate db2) {
    this.db1 = db1;
    this.db2 = db2;
  }
}

因此,我在这两个组件上都有@Component注释,因此我希望能够注册并自动连接。但是,当我运行东西时,我得到以下异常:

创建文件中定义了名为“repository”的bean时出错 [/Users/me/spring/target/classes/my/app/MyRepository.class]: 通过构造函数参数0表示的未满足依赖关系; 嵌套异常是 org.springframework.beans.factory.noSuchBean定义异常:否 “my.app.Db1JdbcTemplate”类型的合格bean可用:应为 至少1个符合autowire候选项资格的bean。依赖项 注释:{}


有什么想法我需要更改什么或者如何进一步调试吗?我总是可以返回到工作版本,但我希望尽可能更加明确,这样编译器可以帮助我,而不是由键入的限定符名称导致的运行时错误。

更标准的方法是避免使用限定符名称中的键入而不是使用限定符注释:

@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Qualifier
public @interface DB1 {
}

@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Qualifier
public @interface DB2 {
} 
然后,在定义bean时:

@Configuration
@ComponentScan
public class AppConfig {
  @Bean
  @ConfigurationProperties(prefix = "db1.datasource")
  @DB1
  public DataSource dataSource1() {
    return DataSourceBuilder.create().build();
  }

  @Bean
  @DB1
  public JdbcTemplate db1(@DB1 DataSource ds) {
    return new JdbcTemplate(ds);
  }

  @Bean
  @ConfigurationProperties(prefix = "db2.datasource")
  @DB2
  public DataSource dataSource2() {
    return DataSourceBuilder.create().build();
  }

  @Bean
  @DB2
  public JdbcTemplate db1(@DB2 DataSource ds) {
    return new JdbcTemplate(ds);
  }
}
public class MyRepository(@DB1 JdbcTemplate db1, @DB2 JdbcTemplate db2) {
    ...
}
最后,在注射豆子时:

@Configuration
@ComponentScan
public class AppConfig {
  @Bean
  @ConfigurationProperties(prefix = "db1.datasource")
  @DB1
  public DataSource dataSource1() {
    return DataSourceBuilder.create().build();
  }

  @Bean
  @DB1
  public JdbcTemplate db1(@DB1 DataSource ds) {
    return new JdbcTemplate(ds);
  }

  @Bean
  @ConfigurationProperties(prefix = "db2.datasource")
  @DB2
  public DataSource dataSource2() {
    return DataSourceBuilder.create().build();
  }

  @Bean
  @DB2
  public JdbcTemplate db1(@DB2 DataSource ds) {
    return new JdbcTemplate(ds);
  }
}
public class MyRepository(@DB1 JdbcTemplate db1, @DB2 JdbcTemplate db2) {
    ...
}

要做到这一点并避免在限定符名称中输入错误,更标准的方法是避免使用限定符名称,而是使用限定符注释:

@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Qualifier
public @interface DB1 {
}

@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Qualifier
public @interface DB2 {
} 
然后,在定义bean时:

@Configuration
@ComponentScan
public class AppConfig {
  @Bean
  @ConfigurationProperties(prefix = "db1.datasource")
  @DB1
  public DataSource dataSource1() {
    return DataSourceBuilder.create().build();
  }

  @Bean
  @DB1
  public JdbcTemplate db1(@DB1 DataSource ds) {
    return new JdbcTemplate(ds);
  }

  @Bean
  @ConfigurationProperties(prefix = "db2.datasource")
  @DB2
  public DataSource dataSource2() {
    return DataSourceBuilder.create().build();
  }

  @Bean
  @DB2
  public JdbcTemplate db1(@DB2 DataSource ds) {
    return new JdbcTemplate(ds);
  }
}
public class MyRepository(@DB1 JdbcTemplate db1, @DB2 JdbcTemplate db2) {
    ...
}
最后,在注射豆子时:

@Configuration
@ComponentScan
public class AppConfig {
  @Bean
  @ConfigurationProperties(prefix = "db1.datasource")
  @DB1
  public DataSource dataSource1() {
    return DataSourceBuilder.create().build();
  }

  @Bean
  @DB1
  public JdbcTemplate db1(@DB1 DataSource ds) {
    return new JdbcTemplate(ds);
  }

  @Bean
  @ConfigurationProperties(prefix = "db2.datasource")
  @DB2
  public DataSource dataSource2() {
    return DataSourceBuilder.create().build();
  }

  @Bean
  @DB2
  public JdbcTemplate db1(@DB2 DataSource ds) {
    return new JdbcTemplate(ds);
  }
}
public class MyRepository(@DB1 JdbcTemplate db1, @DB2 JdbcTemplate db2) {
    ...
}

如果主要问题是拼写错误,只需将名称定义为常量(类似于
公共静态最终字符串DATASOURCE1=“DATASOURCE1”
)并始终在限定符注释中使用这些内容,而不是字符串文字。无需添加新的类或接口。

如果主要问题是拼写错误,只需将名称定义为常量(类似于
public static final string DATASOURCE1=“DATASOURCE1”
)并始终在限定符注释中使用它们,而不是字符串文字。无需添加新的类或接口。

首先,我想找出为什么这不能像我预期的那样工作。然后我可以确定是否需要进行不同的重构。您的配置没有明显的问题。如果nt关于如何进一步调查的想法,这里有3个:1.返回工作解决方案,每次更改一个部分,直到出现问题为止。2.使用断点调试正在找到并初始化的bean。3.更新spring日志,以返回有关bean创建的信息。首先,我想弄清楚为什么is的工作方式与我预期的不一样。然后我可以确定是否需要进行不同的重构。您的配置没有明显的问题。如果您想了解如何进一步调查,以下是3:1。返回工作解决方案,一次只更改一项,直到出现问题。2.使用break指向调试正在找到并初始化哪些bean。3.更新spring日志,以返回有关bean创建的信息。