带有多个JdbcTemplate和Spring Boot的NoSuchBeanDefinitionException

时间:2019-07-03 13:52:57

标签: java spring spring-boot spring-jdbc

我正在使用spring-boot-starter-jdbc并尝试使用多个Jdbc数据源,当我将命名Beans用于我的JdbcTemplate然后使用@Qualifier将正确的JdbcTemplate注入到我的存储库中时,一切正常。

应用程序:

package my.app;

@SpringBootApplication
@EnableAutoConfiguration
public class Application implements CommandLineRunner {

  @Autowired
  private MyRepository repository;

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

  @Override
  public void run(String... args) throws Exception {
    List<Stuff> stuff = repository.getStuff();
  }
}

配置:

package my.app;

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

  @Bean(name = "db1")
  public DataSource db1(@Qualifier("datasource1" DataSource ds) {
    return new JdbcTemplate(ds);
  }

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

  @Bean(name = "db2")
  public DataSource db1(@Qualifier("datasource1" DataSource ds) {
    return new JdbcTemplate(ds);
  }

}

存储库:

package my.app;

@Repository
public class MyRepository {
  private JdbcTemplate db1;
  private JdbcTemplate db2;

  @Autowired
  public class MyRepository(@Qualifier("db1") JdbcTemplate db1, @Qualifier("db2") JdbcTemplate db2) {
    this.db1 = db1;
    this.db2 = db2;
  }
}

当我实例化MyRepository时,一切都很好。

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

这就是我想要做的:

从AppConfig中删除了名为JdbcTemplate的Bean:

package my.app;

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

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

为命名的JdbcTemplates创建了2个新类:

package my.app;

@Component
public class Db1JdbcTemplate extends JdbcTemplate {
  @Autowired
  public Db1JdbcTemplate(@Qualifier("datasource1") DataSource ds1) {
    super(ds1);
  }
} 
package my.app;

@Component
public class Db2JdbcTemplate extends JdbcTemplate {
  @Autowired
  public Db2JdbcTemplate(@Qualifier("datasource2") DataSource ds2) {
    super(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.NoSuchBeanDefinitionException:否   类型为“ my.app.Db1JdbcTemplate”的合格Bean:预期   至少1个符合自动装配候选条件的bean。相依性   注释:{}

有什么想法需要更改或进一步调试吗?我总是可以回到工作版本,但我希望在可能的情况下更明确一些,以便编译器可以帮我解决,而不是由错误的限定符名称引起的运行时错误。

2 个答案:

答案 0 :(得分:2)

一种更标准的方式来避免在限定词名称中出现错别字是避免使用限定词名称,而是使用限定词注释:

@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) {
    ...
}

答案 1 :(得分:0)

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