Spring认证中国教育管理中心-Apache Cassandra 的 Spring 数据教程十

简介: Spring认证中国教育管理中心-Apache Cassandra 的 Spring 数据教程十

13.1.基本
Spring Data 提供了复杂的支持,以透明地跟踪谁创建或更改了实体以及更改发生的时间。要从该功能中受益,您必须为实体类配备审计元数据,这些元数据可以使用注释或通过实现接口来定义。此外,必须通过 Annotation 配置或 XML 配置启用审计以注册所需的基础架构组件。有关配置示例,请参阅特定于商店的部分。

仅跟踪创建和修改日期的应用程序不需要指定AuditorAware.

13.1.1.基于注解的审计元数据
我们提供@CreatedBy并@LastModifiedBy捕获创建或修改实体的用户,@CreatedDate并@LastModifiedDate捕获更改发生的时间。

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

class Customer {

@CreatedBy
private User user;

@CreatedDate
private Instant createdDate;

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

审计元数据不一定需要存在于根级实体中,但可以添加到嵌入式实体中(取决于实际使用的存储),如下面的截图所示。

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

class Customer {

private AuditMetadata auditingMetadata;

// … further properties omitted
}

class AuditMetadata {

@CreatedBy
private User user;

@CreatedDate
private Instant createdDate;

}
13.1.2.基于接口的审计元数据
如果您不想使用注释来定义审计元数据,您可以让您的域类实现该Auditable接口。它公开了所有审计属性的 setter 方法。

13.1.3.AuditorAware
如果您使用@CreatedBy或@LastModifiedBy,审计基础结构需要以某种方式了解当前主体。为此,我们提供了一个AuditorAwareSPI 接口,您必须实现该接口以告知基础设施当前与应用程序交互的用户或系统是谁。泛型类型T定义了用什么类型注释的属性@CreatedBy或@LastModifiedBy必须是什么类型。

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

Example 96.AuditorAware基于 Spring Security 的实现

class SpringSecurityAuditorAware implements AuditorAware {

@Override
public Optional 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发现,您也可以从任何地方查找它。

13.1.4.ReactiveAuditorAware
使用反应式基础架构时,您可能希望使用上下文信息来提供@CreatedBy或提供@LastModifiedBy信息。我们提供了一个ReactiveAuditorAwareSPI 接口,您必须实现该接口才能告诉基础设施当前与应用程序交互的用户或系统是谁。泛型类型T定义了用什么类型注释的属性@CreatedBy或@LastModifiedBy必须是什么类型。

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

例 97.ReactiveAuditorAware基于 Spring Security 的实现

class SpringSecurityAuditorAware implements ReactiveAuditorAware {

@Override
public Mono getCurrentAuditor() {

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

}
}
该实现访问AuthenticationSpring Security 提供的对象并查找UserDetails您在UserDetailsService实现中创建的自定义实例。我们在这里假设您通过UserDetails实现公开域用户,但根据Authentication发现,您也可以从任何地方查找它。

13.2.Cassandra 的一般审计配置
要激活审计功能,请将 Spring Data for Apache Cassandraauditing命名空间元素添加到您的配置中,如以下示例所示:

示例 98. 使用 XML 配置激活审计

<cassandra:auditing mapping-context-ref="customMappingContext" auditor-aware-ref="yourAuditorAwareImpl"/>
或者,可以通过使用注释对配置类进行@EnableCassandraAuditing注释来启用审计,如以下示例所示:

示例 99. 使用 JavaConfig 激活审计

@Configuration
@EnableCassandraAuditing
class Config {

@Bean
public AuditorAware myAuditorProvider() {

  return new AuditorAwareImpl();

}
}
如果你暴露类型的豆AuditorAware到ApplicationContext,审计基础设施自动捡起来,并用它来确定当前用户要在域类型设置。如果您在 中注册了多个实现,则ApplicationContext可以通过显式设置 的auditorAwareRef属性来选择要使用的一个@EnableCassandraAuditing。

要启用审计,利用反应式编程模型,请使用@
EnableReactiveCassandraAuditing注释。
如果你暴露类型的豆ReactiveAuditorAware到ApplicationContext,审计基础设施自动捡起来,并用它来确定当前用户要在域类型设置。如果您在 中注册了多个实现,则ApplicationContext可以通过显式设置 的auditorAwareRef属性来选择要使用的一个@
EnableReactiveCassandraAuditing。

示例 100. 使用 JavaConfig 激活反应式审计

@Configuration
@EnableReactiveCassandraAuditing
class Config {

@Bean
public ReactiveAuditorAware myAuditorProvider() {

  return new AuditorAwareImpl();

}
}

  1. 映射

丰富的对象映射支持由
MappingCassandraConverter. MappingCassandraConverter拥有丰富的元数据模型,提供完整的功能特性集以将域对象映射到 CQL 表。

映射元数据模型是通过使用域对象上的注释来填充的。然而,基础设施不限于使用注释作为元数据的唯一来源。该MappingCassandraConverter还允许你映射域对象到表,而不用提供任何额外的元数据,通过以下一组约定。

在本章中,我们描述了 的特性MappingCassandraConverter,如何使用约定将域对象映射到表,以及如何使用基于注释的映射元数据覆盖这些约定。

14.1.对象映射基础
本节涵盖 Spring Data 对象映射、对象创建、字段和属性访问、可变性和不变性的基础知识。请注意,本节仅适用于不使用底层数据存储(如 JPA)的对象映射的 Spring Data 模块。此外,请务必查阅特定于存储的部分以获取特定于存储的对象映射,例如索引、自定义列或字段名称等。

Spring Data 对象映射的核心职责是创建域对象的实例并将存储本机数据结构映射到这些实例上。这意味着我们需要两个基本步骤:

使用公开的构造函数之一创建实例。
实例填充以实现所有公开的属性。
14.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认证中国教育管理中心-Apache Cassandra 的 Spring 数据教程十
14.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;

}
}
示例 101. 生成的属性访问器

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认证中国教育管理中心-Apache Cassandra 的 Spring 数据教程十
PropertyAccessor 持有底层对象的可变实例。这是为了启用其他不可变属性的突变。

默认情况下,Spring Data 使用字段访问来读取和写入属性值。根据private字段的可见性规则,MethodHandles用于与字段进行交互。

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

使用属性访问允许直接方法调用而不使用MethodHandles.

这使我们比反射提高了大约 25% 的性能。要使域类有资格进行此类优化,它需要遵守一组约束:

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

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

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

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

默认情况下,Spring Data 尝试使用生成的属性访问器,如果检测到限制,则回退到基于反射的访问器。

让我们看一下以下实体:

示例 102. 示例实体

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认证中国教育管理中心-Apache Cassandra 的 Spring 数据教程十
identifier 属性是最终的,但null在构造函数中设置为。该类公开了一个withId(…)用于设置标识符的方法,例如,当一个实例插入到数据存储中并生成一个标识符时。Person创建新实例时,原始实例保持不变。相同的模式通常应用于由存储管理但可能必须为持久性操作更改的其他属性。wither 方法是可选的,因为持久性构造函数(参见 6)实际上是一个复制构造函数,并且设置该属性将被转换为创建一个应用新标识符值的新实例。

的firstname和lastname特性是通过吸气剂可能暴露普通不可变属性。

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

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

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

该类公开了一个工厂方法和一个用于创建对象的构造函数。这里的核心思想是使用工厂方法而不是额外的构造函数,以避免需要通过@PersistenceConstructor. 相反,属性的默认设置是在工厂方法中处理的。

相关文章
|
6月前
|
人工智能 运维 Java
Spring AI Alibaba Admin 开源!以数据为中心的 Agent 开发平台
Spring AI Alibaba Admin 正式发布!一站式实现 Prompt 管理、动态热更新、评测集构建、自动化评估与全链路可观测,助力企业高效构建可信赖的 AI Agent 应用。开源共建,现已上线!
7001 93
|
6月前
|
NoSQL Java 数据库连接
《深入理解Spring》Spring Data——数据访问的统一抽象与极致简化
Spring Data通过Repository抽象和方法名派生查询,简化数据访问层开发,告别冗余CRUD代码。支持JPA、MongoDB、Redis等多种存储,统一编程模型,提升开发效率与架构灵活性,是Java开发者必备利器。(238字)
|
安全 Java Apache
微服务——SpringBoot使用归纳——Spring Boot中集成 Shiro——Shiro 身份和权限认证
本文介绍了 Apache Shiro 的身份认证与权限认证机制。在身份认证部分,分析了 Shiro 的认证流程,包括应用程序调用 `Subject.login(token)` 方法、SecurityManager 接管认证以及通过 Realm 进行具体的安全验证。权限认证部分阐述了权限(permission)、角色(role)和用户(user)三者的关系,其中用户可拥有多个角色,角色则对应不同的权限组合,例如普通用户仅能查看或添加信息,而管理员可执行所有操作。
610 0
|
JSON Java 数据格式
微服务——SpringBoot使用归纳——Spring Boot返回Json数据及数据封装——封装统一返回的数据结构
本文介绍了在Spring Boot中封装统一返回的数据结构的方法。通过定义一个泛型类`JsonResult&lt;T&gt;`,包含数据、状态码和提示信息三个属性,满足不同场景下的JSON返回需求。例如,无数据返回时可设置默认状态码&quot;0&quot;和消息&quot;操作成功!&quot;,有数据返回时也可自定义状态码和消息。同时,文章展示了如何在Controller中使用该结构,通过具体示例(如用户信息、列表和Map)说明其灵活性与便捷性。最后总结了Spring Boot中JSON数据返回的配置与实际项目中的应用技巧。
932 0
|
JSON Java fastjson
微服务——SpringBoot使用归纳——Spring Boot返回Json数据及数据封装——使用 fastJson 处理 null
本文介绍如何使用 fastJson 处理 null 值。与 Jackson 不同,fastJson 需要通过继承 `WebMvcConfigurationSupport` 类并覆盖 `configureMessageConverters` 方法来配置 null 值的处理方式。例如,可将 String 类型的 null 转为 &quot;&quot;,Number 类型的 null 转为 0,避免循环引用等。代码示例展示了具体实现步骤,包括引入相关依赖、设置序列化特性及解决中文乱码问题。
635 0
|
JSON Java fastjson
微服务——SpringBoot使用归纳——Spring Boot返回Json数据及数据封装——Spring Boot 默认对Json的处理
本文介绍了在Spring Boot中返回Json数据的方法及数据封装技巧。通过使用`@RestController`注解,可以轻松实现接口返回Json格式的数据,默认使用的Json解析框架是Jackson。文章详细讲解了如何处理不同数据类型(如类对象、List、Map)的Json转换,并提供了自定义配置以应对null值问题。此外,还对比了Jackson与阿里巴巴FastJson的特点,以及如何在项目中引入和配置FastJson,解决null值转换和中文乱码等问题。
1686 0
|
9月前
|
JSON Java 数据格式
Spring Boot返回Json数据及数据封装
在Spring Boot中,接口间及前后端的数据传输通常使用JSON格式。通过@RestController注解,可轻松实现Controller返回JSON数据。该注解是Spring Boot新增的组合注解,结合了@Controller和@ResponseBody的功能,默认将返回值转换为JSON格式。Spring Boot底层默认采用Jackson作为JSON解析框架,并通过spring-boot-starter-json依赖集成了相关库,包括jackson-databind、jackson-datatype-jdk8等常用模块,简化了开发者对依赖的手动管理。
797 3
|
人工智能 安全 Dubbo
Spring AI 智能体通过 MCP 集成本地文件数据
MCP 作为一款开放协议,直接规范了应用程序如何向 LLM 提供上下文。MCP 就像是面向 AI 应用程序的 USB-C 端口,正如 USB-C 提供了一种将设备连接到各种外围设备和配件的标准化方式一样,MCP 提供了一个将 AI 模型连接到不同数据源和工具的标准化方法。
7771 111
|
存储 NoSQL Java
使用Java和Spring Data构建数据访问层
本文介绍了如何使用 Java 和 Spring Data 构建数据访问层的完整过程。通过创建实体类、存储库接口、服务类和控制器类,实现了对数据库的基本操作。这种方法不仅简化了数据访问层的开发,还提高了代码的可维护性和可读性。通过合理使用 Spring Data 提供的功能,可以大幅提升开发效率。
346 21
|
Java 应用服务中间件 Scala
Spring Boot 实现通用 Auth 认证的 4 种方式
本文介绍了在Spring Boot中实现通用Auth的四种方式:传统AOP、拦截器(Interceptor)、参数解析器(ArgumentResolver)和过滤器(Filter)。每种方式都通过实例代码详细说明了实现步骤,并总结了它们的执行顺序。首先,Filter作为Servlet规范的一部分最先被调用;接着是Interceptor,它可以在Controller方法执行前后进行处理;然后是ArgumentResolver,在参数传递给Controller之前解析并验证参数
315 1

推荐镜像

更多