阿里云-云小站(无限量代金券发放中)
【腾讯云】云服务器、云数据库、COS、CDN、短信等热卖云产品特惠抢购

Spring Data JPA框架的Repository自定义实现详解

55次阅读
没有评论

共计 4204 个字符,预计需要花费 11 分钟才能阅读完成。

导读 Spring Data 提供了各种选项来创建查询方法,只需少量编码。但是当这些选项不能满足你的需求时,你也可以为资源库方法提供你自己的自定义实现。本节主要介绍如何做到这一点。
自定义特殊 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, 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, HumanRepository, ContactRepository {// Declare query methods here}

repository 可以由多个自定义的实现组成,这些实现按其声明的顺序被导入。自定义实现的优先级高于基础实现和 repository 方面。这种排序可以让你覆盖基础 repository 和方面的方法,并在两个片段贡献相同的方法签名时解决歧义。repository 片段不限于在单一 repository 接口中使用。多个 repository 可以使用一个片段接口,让你在不同的 repository 中重复使用定制的内容。

下面的例子显示了一个 repository 片段和它的实现。

例 6. 重写 save(…) 方法的片段代码

public interface CustomSave { S save(S entity);
}
public class CustomSaveImpl implements CustomSave {public  S save(S entity) {// Your custom implementation}
}

例 7 在 repository 接口中扩展例 6 中定义的接口

interface UserRepository extends CrudRepository, CustomSave {
}
interface PersonRepository extends CrudRepository, CustomSave {
}
1.2 配置类

如果你使用命名空间配置,repository 基础设施会尝试通过扫描发现 repository 的包下面的类来自动检测自定义实现片段。这些类需要遵循命名空间元素的 repository-impl-postfix 属性附加到片段接口名称的命名惯例。这个后缀默认为 Impl。下面的例子显示了一个使用默认后缀的 repository 和一个为后缀设置自定义值的 repository。

解决歧义

如果在不同的包中发现有多个类名匹配的实现,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 实现定义的名字相匹配,并被用来代替第一个接口。

手动装配

如果你的自定义实现只使用基于注解的配置和自动装配,前面所示的方法很好用,因为它被当作任何其他 Spring Bean。如果你的实现片段 Bean 需要装配到容器,你可以根据前文所述的约定来声明 Bean 并为其命名。然后,基础设施通过名称来引用手动定义的 Bean 定义,而不是自己创建一个。下面的例子展示了如何手动装配一个自定义的实现。

例 9 手动装配自定义实现类对象到容器

<repositories base-package="com.kkarma.repository"></repositories>
<beans:bean id="userRepositoryImpl" class="…">
  <!-- further configuration -->
</beans:bean>
自定义 Base Repository

当你想定制 base repository 的行为时,上一节描述的方法需要定制每个 repository 的接口,以便所有的 repository 都受到影响。为了改变所有 repository 的行为,你可以创建一个扩展持久化技术特定 repository 基类的实现。然后这个类作为 repository 代理的自定义基类,如下面的例子所示。

例 10 自定义 repository 的基类

class MyRepositoryImpl extends SimpleJpaRepository {
  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 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"></repositories></s></person></user></s></t></s></t>

阿里云 2 核 2G 服务器 3M 带宽 61 元 1 年,有高配

腾讯云新客低至 82 元 / 年,老客户 99 元 / 年

代金券:在阿里云专用满减优惠券

正文完
星哥说事-微信公众号
post-qrcode
 0
星锅
版权声明:本站原创文章,由 星锅 于2024-07-25发表,共计4204字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
【腾讯云】推广者专属福利,新客户无门槛领取总价值高达2860元代金券,每种代金券限量500张,先到先得。
阿里云-最新活动爆款每日限量供应
评论(没有评论)
验证码
【腾讯云】云服务器、云数据库、COS、CDN、短信等云产品特惠热卖中