Spring Data JPA框架Repository自定义实现


Posted in Java/Android onApril 28, 2022

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自定义实现详解的文章就介绍到这了!


Tags in this post...

Java/Android 相关文章推荐
Java常用工具类汇总 附示例代码
Jun 26 Java/Android
Java基础之详解HashSet的使用方法
Jun 30 Java/Android
Spring mvc是如何实现与数据库的前后端的连接操作的?
Jun 30 Java/Android
Java 超详细讲解IO操作字节流与字符流
Mar 25 Java/Android
Java 获取Word中所有的插入和删除修订的方法
Apr 06 Java/Android
Java GUI编程菜单组件实例详解
Apr 07 Java/Android
Java 超详细讲解ThreadLocal类的使用
Apr 07 Java/Android
Android开发之WECHAT微信小程序路由跳转的两种形式
Apr 12 Java/Android
Java 数组的使用
May 11 Java/Android
Android中的Launch Mode详情
Jun 05 Java/Android
Java代码规范与质量检测插件SonarLint的使用
Aug 05 Java/Android
JAVA 线程池(池化技术)的实现原理
Apr 28 #Java/Android
Spring Data JPA框架自定义Repository接口
Apr 28 #Java/Android
Spring Data JPA框架持久化存储数据到数据库
Spring Data JPA框架的核心概念和Repository接口
Java 多态分析
Java由浅入深通关抽象类与接口(下篇)
Java由浅入深通关抽象类与接口(上篇)
You might like
Thinkphp+smarty+uploadify实现无刷新上传
2015/07/30 PHP
PHP简单实现数字分页功能示例
2016/08/24 PHP
学习YUI.Ext 第二天
2007/03/10 Javascript
让低版本浏览器支持input的placeholder属性(js方法)
2013/04/03 Javascript
JavaScript 函数惰性载入的实现及其优点介绍
2013/08/12 Javascript
Jquery搜索父元素操作方法
2015/02/10 Javascript
jquery模拟实现鼠标指针停止运动事件
2016/01/12 Javascript
AngularJs学习第五篇从Controller控制器谈谈$scope作用域
2016/06/08 Javascript
详解Vue 实例中的生命周期钩子
2017/03/21 Javascript
Javascript实现登录记住用户名和密码功能
2017/03/22 Javascript
学习使用ExpressJS 4.0中的新Router的用法
2018/11/06 Javascript
layui实现把数据表格时间戳转换为时间格式的例子
2019/09/12 Javascript
vue在路由中验证token是否存在的简单实现
2019/11/11 Javascript
VUE使用axios调用后台API接口的方法
2020/08/03 Javascript
vue实现在进行增删改操作后刷新页面
2020/08/05 Javascript
js canvas实现五子棋小游戏
2021/01/22 Javascript
three.js 实现露珠滴落动画效果的示例代码
2021/03/01 Javascript
[01:03:42]VP vs VGJ.S 2018国际邀请赛小组赛BO2 第一场 8.19
2018/08/21 DOTA
python常规方法实现数组的全排列
2015/03/17 Python
Python中用Decorator来简化元编程的教程
2015/04/13 Python
python 类详解及简单实例
2017/03/24 Python
pyhanlp安装介绍和简单应用
2019/02/22 Python
python为QT程序添加图标的方法详解
2020/03/09 Python
在HTML5 canvas里用卷积核进行图像处理的方法
2018/05/02 HTML / CSS
GAP美国官网:美国休闲时尚品牌
2016/08/26 全球购物
BLACKMORES澳洲官网:澳大利亚排名第一的保健品牌
2018/09/27 全球购物
三年大学自我鉴定
2014/01/16 职场文书
促销活动总结模板
2014/07/01 职场文书
后进基层党组织整改方案
2014/10/25 职场文书
2015年小学财务工作总结
2015/07/20 职场文书
幼儿体育课教学反思
2016/02/16 职场文书
2016年村干部公开承诺书(公开承诺事项)
2016/03/25 职场文书
话题作文之诚信
2019/11/28 职场文书
MySQL令人大跌眼镜的隐式转换
2021/08/23 MySQL
Win11黑色桌面背景怎么办?Win11黑色壁纸解决方法汇总
2022/04/05 数码科技
引用计数法和root搜索算法以及JVM中判定对象需要回收的方法
2022/04/19 Java/Android