创建自定义存储库以使用Spring Data JPA

时间:2018-12-25 09:41:37

标签: java spring spring-boot spring-data-jpa spring-repositories

我尝试按照以下说明创建custom repository

https://www.baeldung.com/spring-data-jpa-method-in-all-repositories

我的应用构建失败,错误为NoSuchBeanDefinitionException: No qualifying bean of type 'com.example.demo.dao.ExtendedStudentRepository' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}

我的完整源代码

https://github.com/sesong11/springjpa-custom-repo

有很多类似的问题,但是没有一个适合我。也许是当前版本2.1.1的Spring问题,或者我错过了一些配置。

9 个答案:

答案 0 :(得分:3)

要使测试正常进行,您必须执行以下操作:

1)将basePackagesStudentJPAH2Config的错误定义替换为com.example.demo.dao,或者最好将其删除为多余的内容:

@Configuration
@EnableJpaRepositories(repositoryBaseClass = ExtendedRepositoryImpl.class)
public class StudentJPAH2Config {
}

2)还将basePackages中的@ComponentScan@EntityScan类中的DemoApplication替换为com.example.demo.daocom.example.demo.entity。或者最好完全删除这些和@EnableTransactionManagement注释:

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

3)将no-argument constructor添加到实体Student

4)更正您的测试类-使用@DataJpaTest测试DAO层并导入StudentJPAH2Config配置:

@RunWith(SpringRunner.class)
@DataJpaTest
@Import(StudentJPAH2Config.class)
public class ExtendedStudentRepositoryIntegrationTest {
   //...
}

通过这些更正,我已经成功运行了您的测试。

答案 1 :(得分:1)

在运行测试之前,让我们确保主应用程序正在运行。实际上,它存在一些问题。

1。 IllegalArgumentException:不是托管类型:类com.example.demo.entity.Student

问题是 @EntityScan("com.example.demo.entity.*") 。程序包名称不正确,因此不会扫描Student类。

解决方案是@EntityScan("com.example.demo.entity")

2。 PropertyReferenceException:找不到类型attributeContainsText的属性Student

问题在于未设置存储库基类JpaQueryLookupStrategy认为应从方法名称RepositoryQuery构造一个findByAttributeContainsText。它识别出模式findBy{EntityPropertyName},但在attributeContainsText中找不到字段Student

未设置存储库基类,因为未应用配置StudentJPAH2Config。如果无法扫描配置,则不会应用该配置。 @ComponentScan("com.example.demo.dao")不会扫描StudentJPAH2Config所在的软件包。

解决方案是@ComponentScan("com.example.demo"),它将同时扫描"com.example.demo""com.example.demo.dao"软件包 1

现在,当应用程序正常时,让我们回到测试中。

3。 NoSuchBeanDefinitionException:没有可用的com.example.demo.dao.ExtendedStudentRepository类型的合格bean。

问题在于 StudentJPAH2Config不能构成整个配置,并且缺少一些bean。

解决方案是列出所有配置类。

@ContextConfiguration(classes = { StudentJPAH2Config.class, DemoApplication.class })

@ContextConfiguration(classes = DemoApplication.class)

@SpringBootTest

4。 JpaSystemException:没有实体com.example.demo.entity.Student的默认构造函数。

问题在于,休眠 2 需要Student的默认构造函数

@Entity
public class Student {

    @Id
    private long id;
    private String name;

    public Student() {}

    public Student(int id, String name) {
        this.id = id;
        this.name = name;
    }

    // getters & setters

}

1 @ComponentScan("com.example.demo.dao")是多余的,因为其中的@SpringBootApplication将被扫描此软件包。
2 休眠是Spring应用程序中的默认JPA提供程序。

答案 2 :(得分:0)

进行了以下更改:

@SpringBootApplication
@ComponentScan("com.example.demo.dao")
@EntityScan("com.example.demo.entity")
@EnableJpaRepositories(basePackages = "com.example.demo.dao",
        repositoryBaseClass = ExtendedRepositoryImpl.class)
@EnableTransactionManagement
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }


}

和StudentJPAH2Config类

@Configuration
@ComponentScan("com.example.demo")
@EnableJpaRepositories(basePackages = "com.example.demo.dao",
        repositoryBaseClass = ExtendedRepositoryImpl.class)
public class StudentJPAH2Config {
    // additional JPA Configuration
}

缺少空构造函数的学生类:

@Entity
public class Student {

    public Student() {
    }

    public Student(long id, String name) {
        this.id = id;
        this.name = name;
    }

    @Id
    private long id;
    private String name;

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

结果

enter image description here

和应用程序运行状态

enter image description here

答案 3 :(得分:0)

您的自定义Spring Data JPA存储库基类的实现确实起作用。 Spring Boot Application Context中只有几项需要解决。您确实已将Spring Boot Starter模块声明为依赖项,所以我提交了pull request,其中所做的更改将所有手动配置上下文的责任移交给了Spring Auto Configuration工厂提供程序。

这里有一些有关通过测试所需的更改的注释,以及每个测试的一些简短详细信息。注意,要在测试范围之外运行Spring Boot Application,您将需要向类路径添加适当的JDBC供应商依赖项,以及任何Spring应用程序属性以定义数据源属性。定义数据源属性后,Spring Auto Config应该使用合理的设置来照顾任何EntityManager和TransactionManager。参见Spring Boot features - Working with SQL Databases

更改说明:

  • 删除了所有Spring Configuration注释(@SpringBootApplication@EnableJpaRepositories除外)。应用程序pom配置为依赖Spring Boot Starter模块,这些模块已经通过spring.factories提供了Spring Auto Configuration类,同时还确保满足所有其他依赖性。
  • @EnableJpaRepositories不需要声明basePackages,因为Auto Config模块将默认使用Spring Main Application类下的所有软件包。仍然需要声明附加的repositoryBaseClass
  • @ComponentScan已删除,因为“自动配置”模块将对Spring Main Application类之下的所有软件包执行ComponentScan,该软件包已经在项目的顶级软件包中。此外,这是声明basePackages扫描不包含@ConfigurationStudentJPAH2Config类的值。
  • @EntityScan已删除,因为“自动配置”模块将在Spring Main Application类下的所有软件包中执行扫描。
  • @EnableTransactionManagement已删除,因为“自动配置”模块将执行相同的操作。
  • 已删除默认application.properties,因为它们依赖于H2,但是pom仅在测试范围的类路径中提供了该依赖。此外,属性文件中设置的所有配置属性通常在存在H2时由Spring Starters自动配置。
  • Student上为休眠添加了默认的构造函数。除非使用@PersistenceConstructor@Immutable,否则Hibernate在管理实体时需要此构造函数。
  • ExtendedStudentRepositoryIntegrationTest中为单元测试应用程序上下文配置了
  • Spring Boot Auto Configuration。这与在DemoApplicationTests中为Spring Boot集成测试定义的上下文配置相同。当直接将@ContextConfigurationStudentJPAH2Config一起使用时,在Spring Boot Main Application类上定义的配置(即ComponentScan,EntityScan,TransactionManagement)没有应用到Spring Test Application Context。

关于Spring Auto Configuration的一些说明,因为这是阻碍该项目成功运行的主要问题:

Spring Application Starters(通常)分为两种类型的依赖项。

  • autoconfigure模块在​​其POM中声明了最小的依赖关系集,但是在编译过程中构建了许多依赖关系。自动配置模块还通过位于包Configuration中的spring.factories文件来通告META-INF类和工厂。 Spring Boot在引导阶段将加载这些配置类。最后,配置类将有选择地声明Bean,并根据在上下文中声明的其他Bean以及在类路径上实际找到的依赖项来进行其他应用程序上下文更改/增强。这允许根据要导入的库和最少的属性集进行常规/合理的默认配置。
  • starter模块(通常)不提供太多/任何类。它们的目的是提供POM,这些POM声明特定Spring项目的良好开发基线所需的依赖关系。启动程序模块还依赖于适用的autoconfigure模块,这些模块与这些依赖项配对,使您可以快速开始使用应用程序运行。

在大多数情况下,使用Spring Starters时,主驱动程序不应弄清楚需要在Spring上下文中手动配置的内容,而应该弄清楚在基线不适合您的情况下应取消配置的内容。当像您一样在线上关注以下教程/示例时,请记住,可能会显示一些与配置有关的项目。有时可能需要这些配置说明,但通常它们是为了显示非启动Spring应用程序所需的配置细节或透明性。

答案 4 :(得分:-1)

您需要在实现的类中添加注释。 您必须添加@Component或@Service批注,以使Spring能够进行注入

@Component
public class ExtendedRepositoryImpl<T, ID extends Serializable>
extends SimpleJpaRepository<T, ID> implements ExtendedRepository<T, ID> {

答案 5 :(得分:-1)

我认为您忘了对ExtendedStudentRepository bean进行注释

package com.example.demo.dao;

import com.example.demo.entity.Student;
@Repository
public interface ExtendedStudentRepository extends ExtendedRepository<Student, Long> {
}

答案 6 :(得分:-1)

您需要进行以下更改才能解决此问题。另外,由于我本地没有JDK 11,因此我使用JDK 8执行了此操作。另外,我为了扩展问题而执行了ExtendedStudentRepositoryIntegrationTest.java。

  1. 在StudentJPAH2Config.java中,需要添加组件扫描。
@Configuration
@ComponentScan("com.example.demo")
@EnableJpaRepositories(basePackages = "com.example.demo.dao", 
  repositoryBaseClass = ExtendedRepositoryImpl.class)
public class StudentJPAH2Config {
  1. 在DemoApplication中,必须更正基本程序包名称。
@SpringBootApplication
@ComponentScan("com.example.demo.dao")
@EntityScan("com.example.demo.entity")
@EnableTransactionManagement
public class DemoApplication {

更改#1的原因是测试配置中没有组件扫描,spring无法在正确的软件包中查找依赖项。 #2是必需的,因为Student.java直接位于com.example.demo.entity包中,而不是在其任何子包中。您也可以在测试配置文件StudentJPAH2Config中指定@EntityScan,尽管这不是必需的。

现在,这解决了您面临的紧迫问题,但是仍然可以通过一些其他非常直接的问题来欢迎您,并且您可以从这里着手解决。

答案 7 :(得分:-1)

您必须在@Primary类上添加ExtendedRepositoryImpl注释。应该可以。

Spring基本上不能限定依赖项。 @Primary将确保无论您在何处注入对ExtendedRepository接口的依赖项,第一个合格bean(类)将是ExtendedRepositoryImpl

答案 8 :(得分:-1)

您必须删除@ContextConfiguration(classes = { StudentJPAH2Config.class })并在测试类@SpringBootTest上添加ExtendedStudentRepositoryIntegrationTest注释,这将解决您目前遇到的错误NoSuchBeanDefinitionException

但是我又遇到了类似的错误:

Caused by: java.lang.IllegalArgumentException: Not a managed type: class com.example.demo.entity.Student

这是因为Spring无法扫描实体Student

为此,您必须将@EntityScan("com.example.demo.entity.*")类的@EntityScan("com.example.demo.entity")更改为DemoApplication

再次出现错误:

Caused by: org.springframework.data.mapping.PropertyReferenceException: No property attributeContainsText found for type Student!

这是因为方法findByAttributeContainsText()不是有效的方法。