Spring @ComponentScan 无法自动创建由@Repository 注释的 class 的可能原因

What are possible causes for Spring @ComponentScan being unable to auto create a class anotated by @Repository

我遇到了一个 tutorial,它似乎适合我的用例并尝试实现它。我失败了,但不知道为什么。所以我试图找到另一个具有类似代码的示例并查看了书 "Spring in Action, Fourth Edition by Craig Walls"

书籍在第 300 页描述了相同的基本方法。先定义一个JdbcTemplate Bean。

@Bean
NamedParameterJdbcTemplate jdbcTemplate(DataSource dataSource) {
    return new NamedParameterJdbcTemplate(dataSource);
}

然后是实现接口的存储库

@Repository
public class CustomRepositoryImpl implements CustomRepository {

private final NamedParameterJdbcOperations jdbcOperations;

private static final String TEST_STRING = "";

@Autowired
public CustomRepositoryImpl(NamedParameterJdbcOperations jdbcOperations) {
    this.jdbcOperations = jdbcOperations;
}

所以我确实喜欢书中的例子建议,写了一个测试但是得到了错误信息

Error creating bean with name 'de.myproject.config.SpringJPAPerformanceConfigTest': Unsatisfied dependency expressed through field 'abc'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'de.myproject.CustomRepository' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}

根据我对书籍和教程描述的理解,存储库应该被组件扫描识别为 Bean 定义。

为了对此进行测试,我创建了一个上下文并要求提供所有已注册的 Bean。

AnnotationConfigApplicationContext 
context = new AnnotationConfigApplicationContext();
context.getBeanDefinitionNames()

假设我的存储库不在其中。因此,出于测试目的,我增加了项目中的搜索范围,并将其设置为基础包。显示了所有其他 Bean,但 Repository 除外。

作为组件扫描和自动装配的替代方法,书中描述了将存储库简单地声明为 Bean 的可能性,我也这样做了。

@Bean
public CustomRepository(NamedParameterJdbcOperations jdbcOperations) {
    return new CustomRepositoryImpl(jdbcOperations);
}

在那之后 Spring 能够连接存储库。我看了书的github code,希望能更好地理解,但不幸的是那里只实现了运行的Bean解决方案。

所以这是我的问题:

1.) Bean定义有哪些可能的原因,像这样的场景,组件扫描不识别吗?

2.) 这个项目已经使用了 Spring JPA 数据存储库,有什么理由不能同时使用这两种方法吗?

问题是您的 classes 的命名。这里有很多东西需要理解。

  1. 您定义存储库接口 @Repository 是可选的,前提是它扩展了 CRUDRepository 或 spring-data 提供的存储库之一。在此 class 中,您可以声明方法(查找方式...)。而 spring-data 将根据底层数据库制定查询。您还可以使用@Query 指定您的查询。
  2. 假设你有一个涉及复杂查询的方法或一些 spring-data 不能开箱即用的东西,在这种情况下我们可以使用基础模板 class 例如 JdbcTemplate 或 MongoTemplate ..
  3. 执行此操作的过程是创建另一个接口和一个 Impl class。这个接口的命名应该和 Custom 完全一样,你的 Impl class 应该命名为 Impl.. 并且都应该在同一个包中。

例如,如果您的存储库名称是 AbcRepository,那么您的自定义存储库应命名为 AbcRepositoryCustom,实现应命名为 AbcRepositoryImpl。AbcRepository 扩展了 AbcRepositoryCustom(以及其他 spring-数据存储库)。并且 AbcRepositoryImpl 实现了 AbcRepositoryCustom

我自己 "solve" 解决了这个问题。

因为我们也有一个前端 class 为 @ComponentScan

注释了相同的 basePackage
@EnableWebMvc
@Configuration
@ComponentScan(basePackages = {"de.myproject.*"})

所以实际上有两个相同的 @ComponentScans 注释我没有意识到,这确实导致了冲突。它接缝整个应用程序必须加载的顺序已经改变,但这只是我的猜测。

我只是将 Repository 及其 Impl 移动到一个子包中,并更改了

@ComponentScan(basePackages = {"de.myproject.subpackage.*"}) 

现在一切正常。虽然它逃脱了我,但这种行为背后的确切原因是什么。