要用自定义功能丰富存储库,你必须首先定义一个fragment接口和自定义功能的实现,如下所示:
自定义存储库功能的接口
interface CustomizedUserRepository {
void someCustomMethod(User user);
}
自定义存储库功能的实现
class CustomizedUserRepositoryImpl implements CustomizedUserRepository {
public void someCustomMethod(User user) {
// Your custom implementation
}
}
与fragment接口相对应的类名中最重要的部分是Impl后缀。
实现本身不依赖于Spring Data,可以是一个常规的Spring bean。因此,你可以使用标准的依赖注入行为来注入对其他bean(如JdbcTemplate)的引用,参与aspects,等等。
然后,你可以让你的存储库接口扩展fragment接口,如下所示:
对存储库接口的更改
interface UserRepository extends CrudRepository<User, Long>, CustomizedUserRepository {
// Declare query methods here
}
使用你的存储库接口扩展fragment接口将CRUD和自定义功能结合起来,使其可用于客户端。
Spring Data存储库是通过使用组成存储库组合的fragments来实现的。Fragments是基础存储库、功能切面(如QueryDsl)和自定义接口及他们的实现。每次向存储库接口添加接口时,都会通过添加fragment来增强组合。基本存储库和存储库切面的实现由每个Spring Data模块提供。
以下示例展示了自定义接口及其实现:
Fragments及其实现
interface HumanRepository {
void someHumanMethod(User user);
}
class HumanRepositoryImpl implements HumanRepository {
public void someHumanMethod(User user) {
// Your custom implementation
}
}
interface ContactRepository {
void someContactMethod(User user);
User anotherContactMethod(User user);
}
class ContactRepositoryImpl implements ContactRepository {
public void someContactMethod(User user) {
// Your custom implementation
}
public User anotherContactMethod(User user) {
// Your custom implementation
}
}
下面的示例展示了扩展CrudRepository的自定义存储库的接口:
对存储库接口的更改
interface UserRepository extends CrudRepository<User, Long>, HumanRepository, ContactRepository {
// Declare query methods here
}
存储库可以由多个自定义实现组成,这些实现按照声明的顺序导入。自定义实现的优先级高于基本实现和存储库切面。这种排序使您可以覆盖基本存储库和切面方法,并在两个fragments提供相同的方法签名时解决歧义。存储库fragments不限于在单个存储库接口中使用。多个存储库可能使用一个fragment接口,允许你在不同的存储库中重用自定义。
以下示例展示了一个存储库fragment及其实现:
Fragments覆盖save(…)
interface CustomizedSave<T> {
<S extends T> S save(S entity);
}
class CustomizedSaveImpl<T> implements CustomizedSave<T> {
public <S extends T> S save(S entity) {
// Your custom implementation
}
}
下面的示例展示了使用上述存储库片段的存储库:
自定义存储库接口
interface UserRepository extends CrudRepository<User, Long>, CustomizedSave<User> {
}
interface PersonRepository extends CrudRepository<Person, Long>, CustomizedSave<Person> {
}
存储库基础结构试图通过扫描在其中找到存储库的包下面的类来自动检测自定义实现片段(fragments)。这些类需要遵循将后缀默认追加Impl的命名约定。
以下示例展示了一个使用默认后缀的存储库和一个为后缀设置自定义值的存储库:
例1:配置示例
<repositories base-package="com.acme.repository" />
<repositories base-package="com.acme.repository" repository-impl-postfix="MyPostfix" />
@EnableMongoRepositories(repositoryImplementationPostfix = "MyPostfix")
class Configuration { … }
前面示例中的第一个配置试图查找一个名为“com.acme.repository.CustomizedUserRepositoryImpl”的类,以充当自定义存储库实现。第二个示例试图查找“com.acme.repository.CustomizedUserRepositoryMyPostfix”。
如果在不同的包中找到多个具有匹配类名的实现,那么Spring Data将使用bean名称来确定要使用哪一个。
给定前面显示的CustomizedUserRepository的以下两个自定义实现,将使用第一个实现。它的bean名称是customizedUserRepositoryImpl,它与fragment接口(CustomizedUserRepository)加上后缀Impl的名称相匹配。
例2:解决(Resolution)不明确的实现
package com.acme.impl.one;
class CustomizedUserRepositoryImpl implements CustomizedUserRepository {
// Your custom implementation
}
Copied!
package com.acme.impl.two;
@Component("specialCustomImpl")
class CustomizedUserRepositoryImpl implements CustomizedUserRepository {
// Your custom implementation
}
如果你用@Component(“specialCustom”)注解UserRepository接口,那么bean名称加上Impl将与“com.acme.impl.two”中为存储库实现定义的名称相匹配,并使用它来代替第一个。
如果你的自定义实现仅使用基于注解的配置和自动装配,那么前面展示的方法效果很好,因为它被当成任何其他Spring bean。如果你的实现fragment bean需要特殊的装配,那么你可以声明bean并根据上一节中描述的约定对其进行命名。然后,基础结构(infrastructure)通过名称引用手动定义的bean定义,而不是自己创建一个定义。以下示例展示了如何手动装配自定义实现:
例3:手动装配自定义实现
<repositories base-package="com.acme.repository" />
<beans:bean id="userRepositoryImpl" class="…">
beans:bean>
class MyClass {
MyClass(@Qualifier("userRepositoryImpl") UserRepository userRepository) {
…
}
}
当你想要自定义基本存储库行为以使所有存储库都受到影响时,上一节中描述的方法需要自定义每个存储库接口。要更改所有存储库的行为,可以创建一个扩展特定持久性技术存储库基类的实现。然后,该类充当存储库代理的自定义基类,如以下示例所示:
自定义存储库基类
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
}
}
该类需要有一个父类的构造函数,特定存储的存储库工厂实现使用该构造函数。如果存储库基类有多个构造函数,请重写采用EntityInformation加上特定于存储库的基础结构对象(如EntityManager或template类)的构造函数。
最后一步是让Spring Data基础结构了解定制的存储库基类。在配置中,你可以使用repositoryBaseClass来执行此操作,如以下示例所示:
例4:配置自定义存储库基类
<repositories base-package="com.acme.repository"
base-class="….MyRepositoryImpl" />
@Configuration
@EnableMongoRepositories(repositoryBaseClass = MyRepositoryImpl.class)
class ApplicationConfiguration { … }