原题目:Spring认证中国教育管理中心-Spring Data Couchbase教程六(Spring中国教育管理中心)

Spring Data Couchbase教程六
4.6.Spring Data Repository 的自定义实现
Spring Data 提供了各种选项来创立简直不须要编码的查询方法。然而当这些选项不能满足您的需要时,您还能够为存储库办法提供您本人的自定义实现。本节介绍如何执行此操作。

4.6.1.自定义单个存储库
要应用自定义功能丰富存储库,您必须首先为自定义性能定义片段接口和实现,如下所示:

示例 50. 自定义存储库性能的接口

interface CustomizedUserRepository {
void someCustomMethod(User user);
}
示例 51. 自定义存储库性能的实现

class CustomizedUserRepositoryImpl implements CustomizedUserRepository {

public void someCustomMethod(User user) {

// Your custom implementation

}
}
与片段接口对应的类名中最重要的局部是Impl后缀。

实现自身不依赖于 Spring Data,能够是惯例的 Spring bean。因而,您能够应用规范的依赖注入行为来注入对其余 bean 的援用(例如 a JdbcTemplate),参加切面等等。

而后能够让你的repository接口扩大fragment接口,如下:

示例 52. 对存储库界面的更改

interface UserRepository extends CrudRepository<User, Long>, CustomizedUserRepository {

// Declare query methods here
}
应用存储库接口扩大片段接口联合了 CRUD 和自定义性能,并使其可供客户端应用。

Spring Data 存储库是通过应用形成存储库组合的片段来实现的。片段是根底存储库、性能方面(例如QueryDsl)和自定义接口及其实现。每次将接口增加到存储库接口时,都会通过增加片段来加强组合。根本存储库和存储库方面的实现由每个 Spring Data 模块提供。

以下示例显示了自定义接口及其实现:

示例 53. 片段及其实现

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

}
}
Spring Data Couchbase教程六
以下示例显示了扩大的自定义存储库的接口CrudRepository:

示例 54. 对存储库界面的更改

interface UserRepository extends CrudRepository<User, Long>, HumanRepository, ContactRepository {

// Declare query methods here
}
存储库可能由多个按其申明程序导入的自定义实现组成。自定义实现具备比根本实现和存储库方面更高的优先级。此排序容许您笼罩根本存储库和方面办法,并在两个片段奉献雷同的办法签名时解决歧义。存储库片段不限于在单个存储库界面中应用。多个存储库能够应用一个片段接口,让您能够在不同的存储库中重用自定义。

以下示例显示了存储库片段及其实现:

示例 55. 片段笼罩 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

}
}
以下示例显示了应用上述存储库片段的存储库:

示例 56. 自定义存储库接口

interface UserRepository extends CrudRepository<User, Long>, CustomizedSave<User> {
}

interface PersonRepository extends CrudRepository<Person, Long>, CustomizedSave<Person> {
}
配置
如果您应用命名空间配置,存储库根底构造会尝试通过扫描找到存储库的包下的类来自动检测自定义实现片段。这些类须要遵循将命名空间元素的repository-impl-postfix属性附加到片段接口名称的命名约定。此后缀默认为Impl. 以下示例显示了应用默认后缀的存储库和为后缀设置自定义值的存储库:

示例 57. 配置示例

<repositories base-package="com.acme.repository" />

<repositories base-package="com.acme.repository" repository-impl-postfix="MyPostfix" />
后面示例中的第一个配置尝试查找一个称为
com.acme.repository.CustomizedUserRepositoryImpl作为自定义存储库实现的类。第二个示例尝试查找com.acme.repository.CustomizedUserRepositoryMyPostfix。

歧义的解决
如果在不同的包中找到多个具备匹配类名的实现,Spring Data 会应用 bean 名称来辨认要应用哪一个。

鉴于CustomizedUserRepository后面所示的以下两个自定义实现,应用第一个实现。它的 bean 名称
customizedUserRepositoryImpl与片段 interface( CustomizedUserRepository) 加上后缀的名称相匹配Impl。

示例 58. 歧义实现的解决

package com.acme.impl.one;

class CustomizedUserRepositoryImpl implements CustomizedUserRepository {

// Your custom implementation
}
package com.acme.impl.two;

@Component("specialCustomImpl")
class CustomizedUserRepositoryImpl implements CustomizedUserRepository {

// Your custom implementation
}
如果您应用 正文UserRepository接口@Component("specialCustom"),则 bean 名称 plusImpl与 中为存储库实现定义的名称相匹配com.acme.impl.two,并且应用它而不是第一个。

手动接线
如果您的自定义实现仅应用基于正文的配置和主动拆卸,那么后面显示的办法成果很好,因为它被视为任何其余 Spring bean。如果你的实现片段 bean 须要非凡的连贯,你能够申明这个 bean 并依据上一节中形容的约定命名它。而后,基础设施按名称援用手动定义的 bean 定义,而不是本人创立一个。以下示例显示了如何手动连贯自定义实现:

示例 59. 自定义实现的手动连贯

<repositories base-package="com.acme.repository" />

<beans:bean id="userRepositoryImpl" class="…">
<!-- further configuration -->
</beans:bean>
4.6.2.自定义根底存储库
当您想要自定义根本存储库行为以便影响所有存储库时,上一节中形容的办法须要自定义每个存储库接口。要改为更改所有存储库的行为,您能够创立一个扩大特定于持久性技术的存储库基类的实现。而后,此类充当存储库代理的自定义基类,如以下示例所示:

示例 60. 自定义存储库基类

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或一个模板类)的构造函数。

最初一步是让 Spring Data 基础设施理解定制的存储库基类。在 Java 配置中,您能够应用注解的repositoryBaseClass属性来执行此操作@Enable${store}Repositories,如下例所示:

示例 61. 应用 JavaConfig 配置自定义存储库基类

@Configuration
@EnableJpaRepositories(repositoryBaseClass = MyRepositoryImpl.class)
class ApplicationConfiguration { … }
XML 命名空间中提供了相应的属性,如以下示例所示:

示例 62. 应用 XML 配置自定义存储库基类

<repositories base-package="com.acme.repository"

 base-class="….MyRepositoryImpl" />

4.7.从聚合根公布事件
存储库治理的实体是聚合根。在畛域驱动设计应用程序中,这些聚合根通常公布畛域事件。Spring Data 提供了一个注解@DomainEvents,您能够在聚合根的办法上应用该注解,以使公布尽可能简略,如以下示例所示:

示例 63. 从聚合根公开域事件

class AnAggregateRoot {

@DomainEvents Collection<Object> domainEvents() {    // … return events you want to get published here}@AfterDomainEventPublication void callbackMethod() {   // … potentially clean up domain events list}

}
应用的办法@DomainEvents能够返回单个事件实例或事件汇合。它不能有任何论据。

在所有事件都公布后,咱们有一个用 正文的办法@
AfterDomainEventPublication。您能够应用它来潜在地清理要公布的事件列表(以及其余用处)。

该办法被称为一个Spring数据存储库的每一次一个save(…),saveAll(…),delete(…)或deleteAll(…)办法被调用。

4.8.Spring 数据扩大
本节记录了一组 Spring Data 扩大,这些扩大反对 Spring Data 在各种上下文中的应用。目前,大部分集成都是针对 Spring MVC 的。

4.8.1.Querydsl 扩大
Querydsl是一个框架,能够通过其晦涩的 API 构建动态类型的相似 SQL 的查问。

几个 Spring Data 模块通过 Querydsl 提供集成QuerydslPredicateExecutor,如以下示例所示:


64.QuerydslPredicateExecutor 接口

public interface QuerydslPredicateExecutor<T> {

Optional<T> findById(Predicate predicate);

Iterable<T> findAll(Predicate predicate);

long count(Predicate predicate);

boolean exists(Predicate predicate);

// … more functionality omitted.
}
查找并返回与 匹配的单个实体Predicate。

查找并返回与 匹配的所有实体Predicate。

返回与 匹配的实体数Predicate。

返回匹配的实体是否Predicate存在。

要应用 Querydsl 反对,请QuerydslPredicateExecutor在存储库接口上进行扩大,如以下示例所示:

示例 65. 存储库上的 Querydsl 集成

interface UserRepository extends CrudRepository<User, Long>, QuerydslPredicateExecutor<User> {
}
后面的示例容许您应用 QuerydslPredicate实例编写类型平安的查问,如以下示例所示:

Predicate predicate = user.firstname.equalsIgnoreCase("dave")

.and(user.lastname.startsWithIgnoreCase("mathews"));

userRepository.findAll(predicate);