原题目:Spring认证中国教育管理中心-Spring Data R2DBC框架教程四(Spring中国教育管理中心)

14.3.实体回调
Spring Data 基础设施提供了在调用某些办法之前和之后批改实体的钩子。那些所谓的EntityCallback实例提供了一种不便的办法来检查和潜在地以回调格调批改实体。
AnEntityCallback看起来很像一个专门的ApplicationListener. 一些 Spring Data 模块公布BeforeSaveEvent容许批改给定实体的存储特定事件(例如)。在某些状况下,例如应用不可变类型时,这些事件可能会导致麻烦。此外,事件公布依赖于
ApplicationEventMulticaster. 如果应用异步配置TaskExecutor它可能会导致不可预测的后果,因为事件处理能够分叉到线程上。

实体回调为同步 API 和反应式 API 提供集成点,以保障在解决链中定义明确的检查点按程序执行,返回潜在批改的实体或反应式包装器类型。

实体回调通常按 API 类型分隔。这种拆散意味着同步 API 仅思考同步实体回调,而反应式实现仅思考反应式实体回调。

Spring Data Commons 2.2 引入了实体回调 API。这是利用实体批改的举荐形式。在调用可能已注册的实例之前,ApplicationEvents仍会公布特定于现有商店的信息。EntityCallback

14.3.1.实现实体回调
AnEntityCallback通过其泛型类型参数间接与其域类型相关联。每个 Spring Data 模块通常带有一组EntityCallback涵盖实体生命周期的预约义接口。

例 76. 解剖 EntityCallback

@FunctionalInterface
public interface BeforeSaveCallback<T> extends EntityCallback<T> {

/**

  • Entity callback method invoked before a domain object is saved.
  • Can return either the same or a modified instance.
    *
  • @return the domain object to be persisted.
    */

T onBeforeSave(T entity <2>, String collection <3>);
}
BeforeSaveCallback在保留实体之前要调用的特定办法。返回一个可能被批改的实例。

在长久化之前的实体。

许多存储特定参数,例如实体长久化到的汇合。

Spring认证中国教育管理中心-Spring Data R2DBC框架教程四
例 77. 反应式的分析 EntityCallback

@FunctionalInterface
public interface ReactiveBeforeSaveCallback<T> extends EntityCallback<T> {

/**

  • Entity callback method invoked on subscription, before a domain object is saved.
  • The returned Publisher can emit either the same or a modified instance.
    *
  • @return Publisher emitting the domain object to be persisted.
    */

Publisher<T> onBeforeSave(T entity <2>, String collection <3>);
}
BeforeSaveCallback在保留实体之前,在订阅时调用的特定办法。收回一个可能被批改的实例。

在长久化之前的实体。

许多存储特定参数,例如实体长久化到的汇合。

Spring认证中国教育管理中心-Spring Data R2DBC框架教程四
可选的实体回调参数由实现 Spring Data 模块定义并从EntityCallback.callback().

实现适宜您的应用程序需要的接口,如下例所示:

示例 78. 示例 BeforeSaveCallback

class DefaultingEntityCallback implements BeforeSaveCallback<Person>, Ordered {

@Override
public Object onBeforeSave(Person entity, String collection) {

if(collection == "user") {    return // ...}return // ...

}

@Override
public int getOrder() {

return 100;                                                                  

}
}
依据您的要求实现回调。

如果存在多个雷同域类型的实体回调,则可能对实体回调进行排序。排序遵循最低优先级。

Spring认证中国教育管理中心-Spring Data R2DBC框架教程四
14.3.2.注册实体回调
EntityCallback如果 bean 在ApplicationContext. 大多数模板 API 曾经实现ApplicationContextAware,因而能够拜访ApplicationContext

以下示例解释了一组无效的实体回调注册:

示例 79. EntityCallbackBean 注册示例

@Order(1)
@Component
class First implements BeforeSaveCallback<Person> {

@Override
public Person onBeforeSave(Person person) {

return // ...

}
}

@Component
class DefaultingEntityCallback implements BeforeSaveCallback<Person>,

                                                       Ordered { 

@Override
public Object onBeforeSave(Person entity, String collection) {

// ...

}

@Override
public int getOrder() {

return 100;                                                  

}
}

@Configuration
public class EntityCallbackConfiguration {

@BeanBeforeSaveCallback<Person> unorderedLambdaReceiverCallback() {       return (BeforeSaveCallback<Person>) it -> // ...}

}

@Component
class UserCallbacks implements BeforeConvertCallback<User>,

                                    BeforeSaveCallback<User> {   

@Override
public Person onBeforeConvert(User user) {

return // ...

}

@Override
public Person onBeforeSave(User user) {

return // ...

}
}
BeforeSaveCallback从@Order正文中接管其命令。

BeforeSaveCallback通过Ordered接口实现接管其订单。

BeforeSaveCallback应用 lambda 表达式。默认状况下无序并最初调用。请留神,由 lambda 表达式实现的回调不会公开类型信息,因而应用不可调配的实体调用这些会影响回调吞吐量。应用classorenum为回调 bean 启用类型过滤。

在单个实现类中组合多个实体回调接口。

Spring认证中国教育管理中心-Spring Data R2DBC框架教程四
Spring认证中国教育管理中心-Spring Data R2DBC框架教程四
14.3.3.存储特定的 EntityCallbacks
Spring Data R2DBC 应用EntityCallbackAPI 作为其审计反对并对以下回调做出反馈。

Spring认证中国教育管理中心-Spring Data R2DBC框架教程四
14.4.应用多个数据库
当应用多个可能不同的数据库时,您的应用程序将须要不同的配置办法。所提供的
AbstractR2dbcConfiguration反对类假设单个ConnectionFactory从中Dialect失去的。话虽如此,您须要本人定义一些 bean 来配置 Spring Data R2DBC 以解决多个数据库。

R2DBC 存储库须要R2dbcEntityOperations实现存储库。无需应用即可扫描存储库的简略配置
AbstractR2dbcConfiguration如下所示:

@Configuration
@EnableR2dbcRepositories(basePackages = "com.acme.mysql", entityOperationsRef = "mysqlR2dbcEntityOperations")
static class MySQLConfiguration {

@Bean@Qualifier("mysql")public ConnectionFactory mysqlConnectionFactory() {    return …}@Beanpublic R2dbcEntityOperations mysqlR2dbcEntityOperations(@Qualifier("mysql") ConnectionFactory connectionFactory) {    DatabaseClient databaseClient = DatabaseClient.create(connectionFactory);    return new R2dbcEntityTemplate(databaseClient, MySqlDialect.INSTANCE);}

}
请留神,@EnableR2dbcRepositories容许通过databaseClientRef或进行配置entityOperationsRef。DatabaseClient连贯到多个雷同类型的数据库时,应用各种bean 很有用。当应用方言不同的不同数据库系统时,请改用@EnableR2dbcRepositories(entityOperationsRef = ...)`。

15.1.根本
Spring Data 提供了简单的反对,以通明地跟踪谁创立或更改了实体以及更改产生的工夫。要从该性能中受害,您必须为实体类装备审计元数据,这些元数据能够应用正文或通过实现接口来定义。此外,必须通过 Annotation 配置或 XML 配置启用审计以注册所需的基础架构组件。无关配置示例,请参阅特定于商店的局部。

仅跟踪创立和批改日期的应用程序不须要指定AuditorAware.
15.1.1.基于注解的审计元数据

咱们提供@CreatedBy并@LastModifiedBy捕捉创立或批改实体的用户,@CreatedDate并@LastModifiedDate捕捉更改产生的工夫。

示例 80. 一个被审计的实体

class Customer {

@CreatedBy
private User user;

@CreatedDate
private Instant createdDate;

// … further properties omitted
}
如您所见,能够有选择地利用正文,具体取决于您要捕捉的信息。进行更改时捕捉的正文可用于 Joda-Time DateTime、旧版 JavaDate和Calendar、JDK8 日期和工夫类型以及long或类型的属性Long。

审计元数据不肯定须要存在于根级实体中,但能够增加到嵌入式实体中(取决于理论应用的存储),如上面的截图所示。

示例 81. 审计嵌入实体中的元数据

class Customer {

private AuditMetadata auditingMetadata;

// … further properties omitted
}

class AuditMetadata {

@CreatedBy
private User user;

@CreatedDate
private Instant createdDate;

}
15.1.2.基于接口的审计元数据
如果您不想应用正文来定义审计元数据,您能够让您的域类实现该Auditable接口。它公开了所有审计属性的 setter 办法。

15.1.3.AuditorAware
如果您应用@CreatedBy或@LastModifiedBy,审计根底构造须要以某种形式理解以后主体。为此,咱们提供了一个AuditorAware<T>SPI 接口,您必须实现该接口以告知基础设施以后与应用程序交互的用户或零碎是谁。泛型类型T定义了用什么类型正文的属性@CreatedBy或@LastModifiedBy必须是什么类型。

以下示例显示了应用 Spring SecurityAuthentication对象的接口的实现:

Example 82.AuditorAware基于 Spring Security 的实现

class SpringSecurityAuditorAware implements AuditorAware<User> {

@Override
public Optional<User> getCurrentAuditor() {

return Optional.ofNullable(SecurityContextHolder.getContext())        .map(SecurityContext::getAuthentication)        .filter(Authentication::isAuthenticated)        .map(Authentication::getPrincipal)        .map(User.class::cast);

}
}
该实现拜访AuthenticationSpring Security 提供的对象并查找UserDetails您在UserDetailsService实现中创立的自定义实例。咱们在这里假如您通过UserDetails实现公开域用户,但依据Authentication发现,您也能够从任何中央查找它。

15.1.4.ReactiveAuditorAware
应用反应式基础架构时,您可能心愿应用上下文信息来提供@CreatedBy或提供@LastModifiedBy信息。咱们提供了一个ReactiveAuditorAware<T>SPI 接口,您必须实现该接口能力通知基础设施以后与应用程序交互的用户或零碎是谁。泛型类型T定义了用什么类型正文的属性@CreatedBy或@LastModifiedBy必须是什么类型。

以下示例显示了应用响应式 Spring SecurityAuthentication对象的接口的实现:

例 83.ReactiveAuditorAware基于 Spring Security 的实现

class SpringSecurityAuditorAware implements ReactiveAuditorAware<User> {

@Override
public Mono<User> getCurrentAuditor() {

return ReactiveSecurityContextHolder.getContext()            .map(SecurityContext::getAuthentication)            .filter(Authentication::isAuthenticated)            .map(Authentication::getPrincipal)            .map(User.class::cast);

}
}
该实现拜访AuthenticationSpring Security 提供的对象并查找UserDetails您在UserDetailsService实现中创立的自定义实例。咱们在这里假如您通过UserDetails实现公开域用户,但依据Authentication发现,您也能够从任何中央查找它。