Spring认证中国教育管理中心-Spring Data Couchbase教程六

2022年01月14日 阅读数:2
这篇文章主要向大家介绍Spring认证中国教育管理中心-Spring Data Couchbase教程六,主要内容包括基础应用、实用技巧、原理机制等方面,希望对大家有所帮助。

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

Spring认证中国教育管理中心-Spring Data Couchbase教程六_自定义

4.6.Spring Data Repository 的自定义实现

Spring Data 提供了各类选项来建立几乎不须要编码的查询方法。可是当这些选项不能知足您的需求时,您还能够为存储库方法提供您本身的自定义实现。本节介绍如何执行此操做。安全

4.6.1.自定义单个存储库

要使用自定义功能丰富存储库,您必须首先为自定义功能定义片断接口和实现,以下所示:框架

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

interface CustomizedUserRepository {
void someCustomMethod(User user);
}

示例 51. 自定义存储库功能的实现ide

class CustomizedUserRepositoryImpl implements CustomizedUserRepository {

public void someCustomMethod(User user) {
// Your custom implementation
}
}

与片断接口对应的类名中最重要的部分是Impl后缀。函数

实现自己不依赖于 Spring Data,能够是常规的 Spring bean。所以,您可使用标准的依赖注入行为来注入对其余 bean 的引用(例如 a JdbcTemplate),参与切面等等。post

而后可让你的repository接口扩展fragment接口,以下:this

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

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

// Declare query methods here
}

使用存储库接口扩展片断接口结合了 CRUD 和自定义功能,并使其可供客户端使用。spa

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认证中国教育管理中心-Spring Data Couchbase教程六_spring_02

如下示例显示了扩展的自定义存储库的接口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);