乐趣区

关于spring:Spring认证中国教育管理中心Spring-Data-R2DBC框架教程五

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

15.2.R2DBC 的个别审计配置
从 Spring Data R2DBC 1.2 开始,能够通过应用正文对配置类进行 @EnableR2dbcAuditing 正文来启用审计,如下例所示:

示例 84. 应用 JavaConfig 激活审计

@Configuration
@EnableR2dbcAuditing
class Config {

@Bean
public ReactiveAuditorAware<AuditableUser> myAuditorProvider() {

  return new AuditorAwareImpl();

}
}
如果你裸露类型的豆 ReactiveAuditorAware 到 ApplicationContext,审计基础设施主动捡起来,并用它来确定以后用户要在域类型设置。如果您在 中注册了多个实现,则 ApplicationContext 能够通过显式设置 的 auditorAwareRef 属性来抉择要应用的一个 @EnableR2dbcAuditing。

  1. 映射
    提供了丰盛的映射反对 MappingR2dbcConverter。MappingR2dbcConverter 具备丰盛的元数据模型,容许将域对象映射到数据行。映射元数据模型是通过应用域对象上的正文来填充的。然而,基础设施不限于应用正文作为元数据信息的惟一起源。该 MappingR2dbcConverter 还能够让您无需提供任何额定的元数据,通过以下一组约定的映射对象行。

本节介绍 的性能 MappingR2dbcConverter,包含如何应用将对象映射到行的约定以及如何应用基于正文的映射元数据笼罩这些约定。

16.1. 对象映射根底
本节涵盖 Spring Data 对象映射、对象创立、字段和属性拜访、可变性和不变性的基础知识。请留神,本节仅实用于不应用底层数据存储(如 JPA)的对象映射的 Spring Data 模块。此外,请务必查阅特定于存储的局部以获取特定于存储的对象映射,例如索引、自定义列或字段名称等。

Spring Data 对象映射的外围职责是创立域对象的实例并将存储本机数据结构映射到这些实例上。这意味着咱们须要两个根本步骤:

应用公开的构造函数之一创立实例。
实例填充以实现所有公开的属性。
16.1.1. 对象创立
Spring Data 会主动尝试检测要用于具体化该类型对象的长久实体的构造函数。解析算法的工作原理如下:

如果只有一个构造函数,则应用它。
如果有多个构造函数并且只有一个用 正文 @PersistenceConstructor,则应用它。
如果存在无参数构造函数,则应用它。其余构造函数将被疏忽。
值解析假设结构函数参数名称与实体的属性名称匹配,即解析将被执行,就像要填充属性一样,包含映射中的所有自定义(不同的数据存储列或字段名称等)。这还须要类文件中可用的参数名称信息或 @ConstructorProperties 构造函数中存在的正文。

能够通过应用 @Value 特定于商店的 SpEL 表达式应用 Spring Framework 的值正文来自定义值解析。无关更多详细信息,请参阅无关商店特定映射的局部。

对象创立外部

为了防止反射的开销,Spring Data 对象创立默认应用运行时生成的工厂类,它会间接调用域类构造函数。即对于此示例类型:

class Person {
Person(String firstname, String lastname) {…}
}
咱们将在运行时创立一个语义上等同于这个的工厂类:

class PersonObjectInstantiator implements ObjectInstantiator {

Object newInstance(Object… args) {

return new Person((String) args[0], (String) args[1]);

}
}
这使咱们比反射进步了大概 10% 的性能。要使域类有资格进行此类优化,它须要恪守一组束缚:

它不能是私人课程
它不能是非动态外部类
它不能是 CGLib 代理类
Spring Data 应用的构造函数不能是公有的
如果这些条件中的任何一个匹配,Spring Data 将通过反射回退到实体实例化。

Spring 认证中国教育管理中心 -Spring Data R2DBC 框架教程五
16.1.2. 物业人口
一旦创立了实体的实例,Spring Data 就会填充该类的所有残余长久属性。除非实体的构造函数曾经填充(即通过其结构函数参数列表耗费),标识符属性将首先填充以容许循环对象援用的解析。之后,所有尚未由构造函数填充的非瞬态属性都在实体实例上设置。为此,咱们应用以下算法:

如果属性是不可变的但公开了一个 with…办法(见下文),咱们应用该 with…办法创立一个具备新属性值的新实体实例。
如果定义了属性拜访(即通过 getter 和 setter 拜访),咱们将调用 setter 办法。
如果属性是可变的,咱们间接设置字段。
如果属性是不可变的,咱们将应用持久性操作(请参阅对象创立)应用的构造函数来创立实例的正本。
默认状况下,咱们间接设置字段值。
财产人口内部结构

与咱们在对象结构中的优化相似,咱们也应用 Spring Data 运行时生成的拜访器类与实体实例进行交互。

class Person {

private final Long id;
private String firstname;
private @AccessType(Type.PROPERTY) String lastname;

Person() {

this.id = null;

}

Person(Long id, String firstname, String lastname) {

// Field assignments

}

Person withId(Long id) {

return new Person(id, this.firstname, this.lastame);

}

void setLastname(String lastname) {

this.lastname = lastname;

}
}
示例 85. 生成的属性拜访器

class PersonPropertyAccessor implements PersistentPropertyAccessor {

private static final MethodHandle firstname;

private Person person;

public void setProperty(PersistentProperty property, Object value) {

String name = property.getName();

if ("firstname".equals(name)) {firstname.invoke(person, (String) value);             
} else if ("id".equals(name)) {this.person = person.withId((Long) value);            
} else if ("lastname".equals(name)) {this.person.setLastname((String) value);              
}

}
}
Spring 认证中国教育管理中心 -Spring Data R2DBC 框架教程五
Spring 认证中国教育管理中心 -Spring Data R2DBC 框架教程五
PropertyAccessor 持有底层对象的可变实例。这是为了启用其余不可变属性的渐变。

默认状况下,Spring Data 应用字段拜访来读取和写入属性值。依据 private 字段的可见性规定,MethodHandles 用于与字段进行交互。

该类公开了一个 withId(…)用于设置标识符的办法,例如,当一个实例插入到数据存储中并生成一个标识符时。调用 withId(…)创立一个新 Person 对象。所有后续的渐变都将在新实例中产生,而前一个则放弃不变。

应用属性拜访容许间接办法调用而不应用 MethodHandles.

这使咱们比反射进步了大概 25% 的性能。要使域类有资格进行此类优化,它须要恪守一组束缚:

类型不得位于默认值或 java 包下。

类型及其构造函数必须是 public

属于外部类的类型必须是 static.

应用的 Java 运行时必须容许在原始 ClassLoader. Java 9 和更新版本施加了某些限度。

默认状况下,Spring Data 尝试应用生成的属性拜访器,如果检测到限度,则回退到基于反射的拜访器。

让咱们看一下以下实体:

示例 86. 一个示例实体

class Person {

private final @Id Long id;
private final String firstname, lastname;
private final LocalDate birthday;
private final int age;

private String comment;
private @AccessType(Type.PROPERTY) String remarks;

static Person of(String firstname, String lastname, LocalDate birthday) {

return new Person(null, firstname, lastname, birthday,
  Period.between(birthday, LocalDate.now()).getYears());

}

Person(Long id, String firstname, String lastname, LocalDate birthday, int age) {

this.id = id;
this.firstname = firstname;
this.lastname = lastname;
this.birthday = birthday;
this.age = age;

}

Person withId(Long id) {

return new Person(id, this.firstname, this.lastname, this.birthday, this.age);

}

void setRemarks(String remarks) {

this.remarks = remarks;

}
}
Spring 认证中国教育管理中心 -Spring Data R2DBC 框架教程五
identifier 属性是最终的,但 null 在构造函数中设置为。该类公开了一个 withId(…) 用于设置标识符的办法,例如,当一个实例插入到数据存储中并生成一个标识符时。Person 创立新实例时,原始实例放弃不变。雷同的模式通常利用于由存储管理但可能必须为持久性操作更改的其余属性。wither 办法是可选的,因为持久性构造函数(参见 6)实际上是一个复制构造函数,并且设置该属性将被转换为创立一个利用新标识符值的新实例。

的 firstname 和 lastname 个性是通过吸气剂可能裸露一般不可变属性。

该 age 属性是不可变的,但源自该 birthday 属性。应用所示设计,数据库值将胜过默认值,因为 Spring Data 应用惟一申明的构造函数。即便用意是计算应该是首选,重要的是此构造函数也将 age 作为参数(可能会疏忽它),否则属性填充步骤将尝试设置年龄字段并因为它不可变且没有 with…办法而失败在场。

该 comment 属性是可变的,通过间接设置其字段来填充。

的 remarks 个性是可变的,并且通过设置填充 comment 间接字段或通过调用用于 setter 办法

该类公开了一个工厂办法和一个用于创建对象的构造函数。这里的核心思想是应用工厂办法而不是额定的构造函数,以防止须要通过 @PersistenceConstructor. 相同,属性的默认设置是在工厂办法中解决的。

16.1.3. 个别倡议
尽量保持不可变对象 ——不可变对象很容易创立,因为具体化一个对象只是调用它的构造函数的问题。此外,这防止了您的域对象中充斥着容许客户端代码操作对象状态的 setter 办法。如果您须要这些,最好将它们打包爱护,以便它们只能由无限数量的并置类型调用。仅构造函数实现比属性填充快 30%。
提供一个全参数构造函数 ——即便你不能或不想将你的实体建模为不可变值,提供一个将实体的所有属性作为参数的构造函数依然有价值,包含可变的,因为这容许对象映射以跳过属性填充以获得最佳性能。
应用工厂办法而不是重载构造函数来防止 @PersistenceConstructor ——为了获得最佳性能须要一个全参数构造函数,咱们通常心愿公开更多应用程序用例特定的构造函数,这些构造函数省略主动生成的标识符等。这是一种既定的模式,而不是应用动态工厂办法来公开 all-args 构造函数的这些变体。
确保恪守容许应用生成的实例化器和属性拜访器类的束缚 —— 
对于要生成的标识符,依然应用 final 字段与全参数持久性构造函数(首选)或 with…办法相结合 —— 
应用 Lombok 防止样板代码 ——因为持久性操作通常须要一个承受所有参数的构造函数,因而它们的申明变成了对字段调配的样板参数的乏味反复,而应用 Lombok 的 @AllArgsConstructor.
笼罩属性
Java 容许灵便设计畛域类,其中子类能够定义已在其超类中应用雷同名称申明的属性。思考以下示例:

public class SuperType {

private CharSequence field;

public SuperType(CharSequence field) {

  this.field = field;

}

public CharSequence getField() {

  return this.field;

}

public void setField(CharSequence field) {

  this.field = field;

}
}

public class SubType extends SuperType {

private String field;

public SubType(String field) {

  super(field);
  this.field = field;

}

@Override
public String getField() {

  return this.field;

}

public void setField(String field) {

  this.field = field;

  // optional
  super.setField(field);

}
}
Spring 认证中国教育管理中心 -Spring Data R2DBC 框架教程五
这两个类都定义了一个 fieldusing 可调配类型。SubType 然而暗影 SuperType.field。依据类设计,应用构造函数可能是设置 的惟一默认办法 SuperType.field。或者,调用 super.setField(…)setter 能够设置 fieldin SuperType。所有这些机制都会在某种程度上产生抵触,因为属性共享雷同的名称,但可能代表两个不同的值。如果类型不可调配,Spring Data 会跳过超类型属性。也就是说,被笼罩属性的类型必须能够调配给它的超类型属性类型能力注册为笼罩,否则超类型属性被认为是瞬态的。咱们通常倡议应用不同的属性名称。

Spring Data 模块通常反对蕴含不同值的笼罩属性。从编程模型的角度来看,须要思考以下几点:

应该保留哪个属性(默认为所有申明的属性)?您能够通过应用 正文这些属性来排除属性 @Transient。
如何示意数据存储中的属性?对不同的值应用雷同的字段 / 列名称通常会导致数据损坏,因而您应该应用明确的字段 / 列名称来正文至多一个属性。
Using@AccessType(PROPERTY)不能被应用,因为如果不对 setter 实现做任何进一步的假如,通常不能设置超级属性。

退出移动版