Spring Data JPA框架的Repository自定义实现详解
作者:嫣夜来
1. Spring Data Repository自定义实现
Spring Data提供了各种选项来创建查询方法,只需少量编码。但是当这些选项不能满足你的需求时,你也可以为资源库方法提供你自己的自定义实现。本节主要介绍如何做到这一点。
1.1 自定义特殊repository
要用自定义的功能实现来丰富repository库,你必须首先定义一个片段接口和自定义功能的实现,如下所示。
- 例1. 自定义接口
public interface CustomUserRepository { void customMethod(User user); }
- 例2. 自定义接口实现类
public class CustomUserRepositoryImpl implements CustomUserRepository { public void customMethod(User user) { // Your custom implementation } }
实现类本身并不依赖于Spring Data,它可以是一个普通的Spring Bean对象。因此,你可以使用标准的依赖注入行为来注入对其他Bean(如JdbcTemplate)的引用,参与到切面中进行使用等等。
然后你可以让你的repository接口扩展片段接口,如下所示。
- 例3. 修改你的repository接口定义, 让它扩展你自定义接口
public interface UserRepository extends CrudRepository<User, Long>, CustomUserRepository { // Declare query methods here }
这样就用你的repository接口扩展自定义接口,结合了CRUD和自定义功能,并使其对客户端提供服务。
Spring Data repositories是通过使用形成repository组合的片段来实现的。片段是基础repository、功能方面(如QueryDsl),以及自定义接口和它们的实现。每当你为你的repository接口添加一个接口,你就通过添加一个片段来增强组合。基础资源库和资源库方面的实现是由每个Spring Data模块提供的。
下面的例子展示了自定义接口和它们的实现。
- 例4. 片段与它们的实现
public interface HumanRepository { void humanMethod(User user); } public class HumanRepositoryImpl implements HumanRepository { public void humanMethod(User user) { // Your custom implementation } } public interface ContactRepository { void contactMethod1(User user); User contactMethod2(User user); } public class ContactRepositoryImpl implements ContactRepository { public void contactMethod1(User user) { // Your custom implementation } public User contactMethod2(User user) { // Your custom implementation } }
下面的例子显示了一个扩展了CrudRepository的自定义仓库的接口。
- 例5. 修改你的repository接口定义, 让它扩展多个你自定义接口
public interface UserRepository extends CrudRepository<User, Long>, HumanRepository, ContactRepository { // Declare query methods here }
repository可以由多个自定义的实现组成,这些实现按其声明的顺序被导入。自定义实现的优先级高于基础实现和repository方面。这种排序可以让你覆盖基础repository和方面的方法,并在两个片段贡献相同的方法签名时解决歧义。repository片段不限于在单一repository接口中使用。多个repository可以使用一个片段接口,让你在不同的repository中重复使用定制的内容。
下面的例子显示了一个repository片段和它的实现。
- 例6. 重写save(…)方法的片段代码
public interface CustomSave<T> { <S extends T> S save(S entity); } public class CustomSaveImpl<T> implements CustomSave<T> { public <S extends T> S save(S entity) { // Your custom implementation } }
- 例7 在repository接口中扩展例6中定义的接口
interface UserRepository extends CrudRepository<User, Long>, CustomSave<User> { } interface PersonRepository extends CrudRepository<Person, Long>, CustomSave<Person> { }
1.2 配置类
如果你使用命名空间配置,repository基础设施会尝试通过扫描发现repository的包下面的类来自动检测自定义实现片段。这些类需要遵循命名空间元素的repository-impl-postfix属性附加到片段接口名称的命名惯例。这个后缀默认为 Impl。下面的例子显示了一个使用默认后缀的repository和一个为后缀设置自定义值的repository。
XML文件的配置示例
<repositories base-package="com.kkarma.repository" /> <repositories base-package="com.kkarma.repository" repository-impl-postfix="MyImpl" />
前面例子中的第一个配置试图查找一个叫做 com.kkatma.repository.CustomUserRepositoryImpl 的类,作为一个自定义的repository实现。第二个例子试图查找 com.kkarma.repository.CustomUserRepositoryMyImpl。
1.3 解决歧义
如果在不同的包中发现有多个类名匹配的实现,Spring Data会使用bean对象的名字来确定使用哪一个。
考虑到前面显示的CustomUserRepository的以下两个自定义实现,第一个实现被使用。它的bean是customUserRepositoryImpl,与片段接口(CustomUserRepository)加上后缀Impl的名字相匹配。
- 例8 解决歧义实现方式
package com.kkarma.impl.one; class CustomUserRepositoryImpl implements CustomUserRepository { // Your custom implementation }
package com.kkarma.impl.two; @Component("specialCustomImpl") class CustomUserRepositoryImpl implements CustomUserRepository { // Your custom implementation }
如果你用 @Component("specialCustom")
来注解 UserRepository
接口,那么Bean的名字加上 Impl
就与 com.kkarma.impl.two
中为repository实现定义的名字相匹配,并被用来代替第一个接口。
1.4 手动装配
如果你的自定义实现只使用基于注解的配置和自动装配,前面所示的方法很好用,因为它被当作任何其他Spring Bean。如果你的实现片段Bean需要装配到容器,你可以根据前文所述的约定来声明Bean并为其命名。然后,基础设施通过名称来引用手动定义的Bean定义,而不是自己创建一个。下面的例子展示了如何手动装配一个自定义的实现。
- 例9 手动装配自定义实现类对象到容器
<repositories base-package="com.kkarma.repository" /> <beans:bean id="userRepositoryImpl" class="…"> <!-- further configuration --> </beans:bean>
1.5 自定义Base Repository
当你想定制base repository的行为时,上一节描述的方法需要定制每个repository的接口,以便所有的repository都受到影响。为了改变所有repository的行为,你可以创建一个扩展持久化技术特定repository基类的实现。然后这个类作为repository代理的自定义基类,如下面的例子所示。
- 例10 自定义repository的基类
class MyRepositoryImpl<T, ID> extends SimpleJpaRepository<T, ID> { private final EntityManager entityManager; MyRepositoryImpl(JpaEntityInformation entityInformation, EntityManager entityManager) { super(entityInformation, entityManager); // Keep the EntityManager around to used from the newly introduced methods. this.entityManager = entityManager; } @Transactional public <S extends T> S save(S entity) { // implementation goes here } }
最后一步是让Spring Data基础设施意识到自定义的repository基类。在Java配置中,你可以通过使用@Enable${store}Repositories注解的repositoryBaseClass属性来做到这一点,如下面例子所示。
- 例11 使用JavaConfig配置自定义repository基类
@Configuration @EnableJpaRepositories(repositoryBaseClass = MyRepositoryImpl.class) class ApplicationConfiguration { … }
在XML命名空间中有一个相应的属性,如下面的例子中所示。
- 例12 使用XML配置自定义repository基类
<repositories base-package="com.kkarma.repository" base-class="….MyRepositoryImpl" />
到此这篇关于Spring Data JPA框架的Repository自定义实现详解的文章就介绍到这了,更多相关Spring Data JPA Repository内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!