【问题标题】:NoSuchBeanDefinitionException with Multiple JdbcTemplate and Spring BootNoSuchBeanDefinitionException 与多个 JdbcTemplate 和 Spring Boot
【发布时间】:2019-11-14 05:43:10
【问题描述】:

我正在使用 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。依赖 注释:{}

任何想法我需要更改或如何进一步调试?我总是可以回到工作版本,但我希望尽可能更明确,以便编译器可以帮助我,而不是由拼写错误的限定符名称引起的运行时错误。

【问题讨论】:

    标签: java spring spring-boot spring-jdbc


    【解决方案1】:

    执行此操作并避免限定符名称中的拼写错误的更标准方法是避免使用限定符名称,而是使用限定符注释:

    @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);
      }
    }
    

    最后在注入 bean 时:

    public class MyRepository(@DB1 JdbcTemplate db1, @DB2 JdbcTemplate db2) {
        ...
    }
    

    【讨论】:

      【解决方案2】:

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

      【讨论】:

      • 首先我想弄清楚为什么这不像我预期的那样工作。然后我可以确定是否适合进行不同的重构。
      • 您的配置没有明显问题。如果您想了解如何进一步调查,这里有 3 个: 1. 恢复到工作解决方案并一次更改一件,直到出现问题以找到问题。 2. 使用断点来调试正在找到和初始化哪些bean。 3. 更新您的 spring 日志以返回有关 bean 创建的信息。
      猜你喜欢
      • 2016-12-06
      • 1970-01-01
      • 1970-01-01
      • 2015-01-14
      • 1970-01-01
      • 2021-12-08
      • 2023-03-17
      • 2016-05-20
      • 2020-05-17
      相关资源
      最近更新 更多