[英]Create Custom Repository to Spring Data JPA
我尝试按照此教程创建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问题,或者我错过了一些配置。
要使测试正常进行,您必须执行以下操作:
1)将basePackages
中StudentJPAH2Config
的错误定义替换为com.example.demo.dao
,或者最好将其删除为多余的:
@Configuration
@EnableJpaRepositories(repositoryBaseClass = ExtendedRepositoryImpl.class)
public class StudentJPAH2Config {
}
2)亦取代basePackages
在@ComponentScan
和@EntityScan
在DemoApplication
类com.example.demo.dao
和com.example.demo.entity
。 或者最好完全删除这些和@EnableTransactionManagement
批注:
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
3)向实体Student
添加一个无参数的构造函数 。
4)更正您的测试类-使用@DataJpaTest测试DAO层并导入您的StudentJPAH2Config
配置:
@RunWith(SpringRunner.class)
@DataJpaTest
@Import(StudentJPAH2Config.class)
public class ExtendedStudentRepositoryIntegrationTest {
//...
}
通过这些更正,我已经成功运行了您的测试。
在运行测试之前,让我们确保主应用程序正在运行。 实际上,它存在一些问题。
IllegalArgumentException
:不是托管类型: com.example.demo.entity.Student
类。 问题是@EntityScan("com.example.demo.entity.*")
。 软件包名称不正确,因此不扫描Student
类。
解决方案是@EntityScan("com.example.demo.entity")
。
PropertyReferenceException
:找不到类型为Student
属性attributeContainsText
! 问题在于没有设置存储库基类 ,并且JpaQueryLookupStrategy
认为它应该从方法名称findByAttributeContainsText
构造一个RepositoryQuery
。 它识别出模式findBy{EntityPropertyName}
,但在Student
找不到字段attributeContainsText
。
未设置存储库基类,因为未应用配置StudentJPAH2Config
。 如果无法扫描配置,则不会应用该配置。 @ComponentScan("com.example.demo.dao")
不扫描StudentJPAH2Config
所在的包。
解决方案是@ComponentScan("com.example.demo")
,它将扫描"com.example.demo"
和"com.example.demo.dao"
软件包1 。
现在,当应用程序正常时,让我们回到测试中。
NoSuchBeanDefinitionException
:没有可用的com.example.demo.dao.ExtendedStudentRepository
类型的合格Bean。 问题在于StudentJPAH2Config
不能构成整个配置 ,并且缺少一些bean。
解决方案是列出所有配置类。
@ContextConfiguration(classes = { StudentJPAH2Config.class, DemoApplication.class })
要么
@ContextConfiguration(classes = DemoApplication.class)
要么
@SpringBootTest
JpaSystemException
:没有实体com.example.demo.entity.Student
默认构造函数。 问题在于, Hibernate 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 Hibernate是Spring应用程序中的默认JPA提供程序。
进行了以下更改:
@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;
}
}
结果
和应用程序运行状态
您对自定义Spring Data JPA存储库基类的实现确实起作用。 Spring Boot Application Context中只有几项需要解决。 您确实已将Spring Boot Starter模块声明为依赖项,因此我提交了具有更改的Pull请求 ,该更改将将手动配置上下文的所有责任移交给了Spring Auto Configuration工厂提供程序。
以下是有关通过测试所需的一些更改的注释,以及每个更改的一些简短详细信息。 注意,要在测试范围之外运行Spring Boot Application,您将需要向类路径添加适当的JDBC供应商依赖项,以及任何Spring应用程序属性以定义数据源属性。 定义数据源属性后,Spring Auto Config应该使用合理的设置来照顾任何EntityManager和TransactionManager。 请参阅Spring Boot功能-使用SQL数据库 。
@SpringBootApplication
和@EnableJpaRepositories
)。 应用程序pom配置为依赖于Spring Boot Starter模块,这些模块已经通过spring.factories提供了Spring Auto Configuration类,同时还确保满足所有其他依赖性。 @EnableJpaRepositories
不需要声明basePackages
因为Auto Config模块将默认使用Spring Main Application类下面的所有软件包。 仍然需要声明附加的repositoryBaseClass
。 @ComponentScan
被删除,因为Auto Config模块将对Spring Main Application类下的所有软件包执行ComponentScan,该软件包已经在项目的顶级软件包中。 此外,这是声明要扫描的basePackages
值将不包含@Configuration
类StudentJPAH2Config
。 @EntityScan
作为自动配置模块被删除后,将在Spring Main Application类下的所有软件包中执行扫描。 @EnableTransactionManagement
已删除,因为“自动配置”模块将执行相同的操作。 application.properties
因为它们依赖于H2
,但是pom仅在测试范围的类路径中提供了该依赖关系。 此外,属性文件中设置的所有配置属性通常在存在H2时由Spring Starters自动配置。 Student
为休眠添加了默认的构造函数。 除非使用@PersistenceConstructor
或@Immutable
,否则Hibernate在管理实体时需要此构造函数。 ExtendedStudentRepositoryIntegrationTest
为单元测试应用程序上下文配置的Spring Boot自动配置。 这与在DemoApplicationTests
为Spring Boot集成测试定义的上下文配置相同。 当直接将@ContextConfiguration
与StudentJPAH2Config
一起StudentJPAH2Config
,在Spring Boot Main Application类上定义的配置(即ComponentScan,EntityScan,TransactionManagement)未应用到Spring Test Application Context。 Spring Application Starters(通常)分为两种类型的依赖关系。
autoconfigure
模块在其POM中声明了最小的依赖关系集,但是在编译过程中使用许多依赖关系来构建。 自动配置模块还通过位于包的META-INF
中的spring.factories
文件通告Configuration
类和工厂。 Spring Boot在引导阶段将加载这些配置类。 最后,配置类将有选择地声明Bean,并根据在上下文中声明的其他Bean以及在类路径上实际找到的依赖项来进行其他应用程序上下文更改/增强。 这允许所有常规/合理的默认配置,这些配置均基于要引入的库和最少的属性集。 starter
模块(通常)不提供太多/任何类。 它们的目的是提供POM,这些POM声明特定Spring项目的良好开发基线所需的依赖关系。 启动程序模块还依赖于适用的autoconfigure
模块,这些模块与这些依赖项配对,使您可以快速开始使用应用程序运行。 在大多数情况下,使用Spring Starters时,主驱动程序不应弄清楚需要在Spring上下文中手动配置的内容,而应该弄清楚在基线不适合您的情况下应取消配置的内容。 当像您一样在线上关注以下教程/示例时,请记住,可能会显示一些与配置有关的项目。 有时可能需要这些配置说明,但通常它们是为了显示非启动Spring应用程序中所需的配置或透明性的详细信息。
您需要在实现的类中添加注释。 您必须添加@Component或@Service批注,以使Spring能够进行注入
@Component
public class ExtendedRepositoryImpl<T, ID extends Serializable>
extends SimpleJpaRepository<T, ID> implements ExtendedRepository<T, ID> {
我认为您忘了注释ExtendedStudentRepository
bean
package com.example.demo.dao;
import com.example.demo.entity.Student;
@Repository
public interface ExtendedStudentRepository extends ExtendedRepository<Student, Long> {
}
您需要进行以下更改才能解决此问题。 另外,由于我本地没有JDK 11,因此我使用JDK 8执行了此操作。 另外,为了执行问题复制,我执行了ExtendedStudentRepositoryIntegrationTest.java。
@Configuration @ComponentScan("com.example.demo") @EnableJpaRepositories(basePackages = "com.example.demo.dao", repositoryBaseClass = ExtendedRepositoryImpl.class) public class StudentJPAH2Config {
@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,尽管这不是必需的。
现在,这解决了您面临的直接问题,但是仍然可以通过其他一些非常直接的问题来欢迎您,并且您可以从这里继续进行下去。
您必须将@Primary
批注放在ExtendedRepositoryImpl
类上。 它应该工作。
Spring基本上不能限定依赖项。 @Primary
将确保无论您在哪里为ExtendedRepository
接口注入依赖项,首先将合格的bean(class)都为ExtendedRepositoryImpl
。
您必须删除@ContextConfiguration(classes = { StudentJPAH2Config.class })
并在测试类ExtendedStudentRepositoryIntegrationTest
上添加@SpringBootTest
批注,它将解决当前存在的错误NoSuchBeanDefinitionException
。
但是我又遇到了类似的错误:
Caused by: java.lang.IllegalArgumentException: Not a managed type: class com.example.demo.entity.Student
这是因为Spring无法扫描Entity 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()
不是有效的方法。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.