当前位置: 首页 > 工具软件 > GemFire > 使用案例 >

SpringBoot 2 访问 Pivotal GemFire 数据

羊丰茂
2023-12-01

开篇词

该指南将引导你使用 Pivotal GemFire 的数据服务集来构建应用。
 

你将创建的应用

我们将使用功能强大的 Spring Data for Pivotal GemFire 库来存储和检索 POJO。
 

你将需要的工具

如何完成这个指南

像大多数的 Spring 入门指南一样,你可以从头开始并完成每个步骤,也可以绕过你已经熟悉的基本设置步骤。如论哪种方式,你最终都有可以工作的代码。

  • 要从头开始,移步至使用 Gradle 构建
  • 要跳过基础,执行以下操作:
    • 下载并解压缩该指南将用到的源代码,或借助 Git 来对其进行克隆操作:git clone https://github.com/spring-guides/gs-accessing-data-gemfire.git
    • 切换至 gs-accessing-data-gemfire/initial 目录;
    • 跳转至该指南的定义简单的实体

待一切就绪后,可以检查一下 gs-accessing-data-gemfire/complete 目录中的代码。
 

使用 Gradle 来构建

首先,我们搭建一个基本的构建脚本。在使用 Spring 构建应用时,可以使用任何喜欢的构建系统,但此处包含使用 GradleMaven 所需的代码。如果我们都不熟悉,请参阅使用 Gradle 构建 Java 项目使用 Maven 构建 Java 项目

创建目录结构

在我们选择的项目目录中,创建以下自目录结构;例如,在 *nix 系统上使用 mkdir -p src/main/java/hello

└── src
    └── main
        └── java
            └── hello

创建 Gradle 构建文件

以下是初始化的 Gradle 构建文件。
build.gradle

buildscript {
    repositories {
        mavenCentral()
        maven { url "https://repo.spring.io/libs-release" }
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:2.2.1.RELEASE")
    }
}

plugins {
    id "io.spring.dependency-management" version "1.0.5.RELEASE"
}

apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'idea'
apply plugin: 'org.springframework.boot'

sourceCompatibility = 1.8
targetCompatibility = 1.8

bootJar {
    baseName = 'gs-accessing-data-gemfire'
    version = '0.1.0'
}

repositories {
    mavenCentral()
    maven { url "https://repo.spring.io/libs-release" }
}

dependencies {
    compile("org.springframework.boot:spring-boot-starter-web") {
        exclude group: "org.springframework.boot", module: "spring-boot-starter-logging"
    }
    compile("org.springframework.data:spring-data-gemfire")
    compile("org.projectlombok:lombok")
    runtime("org.springframework.shell:spring-shell:1.2.0.RELEASE")
}

Spring Boot gradle 插件提供了许多方便的功能:

  • 它收集类路径上的所有 jar,并构建一个可运行的单个超级 jar,这使执行和传输服务更加方便;
  • 它搜索 public static void main() 方法以将其标记为可运行类;
  • 它提供了一个内置的依赖解析器,用语设置版本号以匹配 Spring Boot 依赖。我们可以覆盖所需的任何版本,但默认为 Boot 选择的一组版本。

 

使用 Maven 来构建

首先,我们搭建一个基本的构建脚本。使用 Spring 构建应用时,可以使用任何喜欢的构建系统,但此处包含使用 Maven 所需的代码。如果你不熟悉 Maven,请参阅使用 Maven 构建 Java 项目

创建目录结构

在我们选择的项目目录中,创建以下自目录结构;例如,在 *nix 系统上使用 mkdir -p src/main/java/hello

└── src
    └── main
        └── java
            └── hello

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">

    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.1.RELEASE</version>
    </parent>

    <groupId>org.springframework</groupId>
    <artifactId>gs-accessing-data-gemfire</artifactId>
    <version>0.1.0</version>

    <properties>
        <spring-shell.version>1.2.0.RELEASE</spring-shell.version>
    </properties>

    <repositories>
        <repository>
            <id>spring-releases</id>
            <url>https://repo.spring.io/libs-release</url>
        </repository>
    </repositories>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-logging</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-gemfire</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.shell</groupId>
            <artifactId>spring-shell</artifactId>
            <version>${spring-shell.version}</version>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

Spring Boot Maven 插件提供了许多方便的功能:

  • 它收集类路径上的所有 jar,并构建一个可运行的单个超级 jar,这使执行和传输服务更加方便;
  • 它搜索 public static void main() 方法以将其标记为可运行类;
  • 它提供了一个内置的依赖解析器,用语设置版本号以匹配 Spring Boot 依赖。我们可以覆盖所需的任何版本,但默认为 Boot 选择的一组版本。

 

使用 IDE 来构建

定义简单的实体

Pivotal GemFire 是一个内存数据网格(IMDG),可将数据映射到区域。可以配置分布式区域,以在集群中的多个节点之间分区和复制数据。但是,在该指南中,我们将使用 LOCAL,因此我们无需做其他准备,例如整个服务器集群等操作。

Pivotal GemFire 是一个键/值存储,而 Region 则实现 java.util.concurrent.ConcurrentMap 接口。尽管我们可以将 Region 当作 java.util.Map 对待,但要比在区域内分发,复制和管理数据的简单 Java Map 复杂得多。

在该示例中,仅使用一些注解将 Person 对象存储在 Pivotal GemFire(一个 Region)中。
src/main/java/hello/Person.java

package hello;

import java.io.Serializable;

import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.PersistenceConstructor;
import org.springframework.data.gemfire.mapping.annotation.Region;

import lombok.Getter;

@Region(value = "People")
public class Person implements Serializable {

  @Id
  @Getter
  private final String name;

  @Getter
  private final int age;

  @PersistenceConstructor
  public Person(String name, int age) {
    this.name = name;
    this.age = age;
  }

  @Override
  public String toString() {
    return String.format("%s is %d years old", getName(), getAge());
  }
}

这里,我们有一个 Person 类,其中包含两个字段,即 nameage。我们还有一个持久的构造函数,用于在创建新实例时填充实体。该类使用 Project Lombok 简化实现。

请注意,该类由 @Region("People") 标注。当 Pivotal GemFire 存储该类的实例时,将在 “People” 区域内创建一个新条目。该类还使用 @Id 标记 name 字段。这表示用于识别和跟踪 Pivotal GemFire 中的 Person 数据的标识符。本质上,@Id 标注的字段(例如 name)是键,Person 实例是键/值条目中的值。Pivotal GemFire 中没有自动生成密钥的功能,因此我们必须先设置 id(即 name),然后再将实体持久保存到 Pivotal GemFire 中。

下一个重要的片段是人的年龄。在该指南之后,我们将使用它来塑造一些查询。

覆盖的 toString() 方法将打印出该人的姓名和年龄。
 

创建简单的查询

Pivotal GemFire 的 Spring Data 专注于使用 Spring 的 Pivotal GemFire 中存储和访问数据。它还从 Spring Data Commons 项目继承了很强大的功能,例如导出查询的功能。本质上,我们不必学习 Pivotal GemFire(OQL)的查询语言;我们只需要写一些方法,框架即可为我们编写查询。

要查看其工作原理,请创建一个查询存储在 Pivotaol GemFire 中 Person 对象的接口。

src/main/java/hello/PersonRepository.java

package hello;

import org.springframework.data.gemfire.repository.query.annotation.Trace;
import org.springframework.data.repository.CrudRepository;

public interface PersonRepository extends CrudRepository<Person, String> {

  @Trace
  Person findByName(String name);

  @Trace
  Iterable<Person> findByAgeGreaterThan(int age);

  @Trace
  Iterable<Person> findByAgeLessThan(int age);

  @Trace
  Iterable<Person> findByAgeGreaterThanAndAgeLessThan(int greaterThanAge, int lessThanAge);

}

PersonRepository 从 Spring Data Commons 扩展了 CrudRepository 接口,并为 Repository 使用的值和 id(key)的通用类型参数指定了类型,分别是 PersonString。该接口开箱即用,具有许多操作,包括基本的 CRUD(CREATE、READ、UPDATE、DELETE)和简单的查询(例如 findById(..))数据访问操作。

我们可以根据需要定义其他查询,只需声明它们的方法签名即可。在这种情况下,我们将添加 findByName,它实际上的搜索类型为 Person 的对象并找到与 name 匹配的对象。

以及:

  • findByAgeGreaterThan 查找超过一定年龄的人;
  • findByAgeLess 查找一定年龄以下的人;
  • findByAgeGreaterThanAndAgeLessThan 查找特定年龄段的人。

我们来看一下它的效果!
 

创建应用类

这里,我们将创建一个拥有所有组件的 Application 类。

src/main/java/hello/Application.java

package hello;

import static java.util.Arrays.asList;
import static java.util.stream.StreamSupport.stream;

import java.io.IOException;

import org.apache.geode.cache.client.ClientRegionShortcut;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.data.gemfire.config.annotation.ClientCacheApplication;
import org.springframework.data.gemfire.config.annotation.EnableEntityDefinedRegions;
import org.springframework.data.gemfire.repository.config.EnableGemfireRepositories;

@SpringBootApplication
@ClientCacheApplication(name = "AccessingDataGemFireApplication", logLevel = "error")
@EnableEntityDefinedRegions(basePackageClasses = Person.class,
  clientRegionShortcut = ClientRegionShortcut.LOCAL)
@EnableGemfireRepositories
public class Application {

  public static void main(String[] args) throws IOException {
    SpringApplication.run(Application.class, args);
  }

  @Bean
  ApplicationRunner run(PersonRepository personRepository) {

    return args -> {

      Person alice = new Person("Adult Alice", 40);
      Person bob = new Person("Baby Bob", 1);
      Person carol = new Person("Teen Carol", 13);

      System.out.println("Before accessing data in Pivotal GemFire...");

      asList(alice, bob, carol).forEach(person -> System.out.println("\t" + person));

      System.out.println("Saving Alice, Bob and Carol to Pivotal GemFire...");

      personRepository.save(alice);
      personRepository.save(bob);
      personRepository.save(carol);

      System.out.println("Lookup each person by name...");

      asList(alice.getName(), bob.getName(), carol.getName())
        .forEach(name -> System.out.println("\t" + personRepository.findByName(name)));

      System.out.println("Query adults (over 18):");

      stream(personRepository.findByAgeGreaterThan(18).spliterator(), false)
        .forEach(person -> System.out.println("\t" + person));

      System.out.println("Query babies (less than 5):");

      stream(personRepository.findByAgeLessThan(5).spliterator(), false)
        .forEach(person -> System.out.println("\t" + person));

      System.out.println("Query teens (between 12 and 20):");

      stream(personRepository.findByAgeGreaterThanAndAgeLessThan(12, 20).spliterator(), false)
        .forEach(person -> System.out.println("\t" + person));
    };
  }
}

在配置中,我们需要添加 @EnableGemfireRepositories 注解。

默认情况下,@EnableGemfireRepositories 将在当前包中扫描任何扩展了 Spring Data 的 Repository 接口之一的接口。使用它的 basePackageClasses = MyRepository.class 来安全地告诉 Spring Data for Pivotal GemFire 以按类型扫描不同的根包,并查找特定于应用的 Repository 扩展。

需要包含一或多个区域的 Pivotal GemFire 缓存来存储所有数据。为此,我们可以使用 Spring Data for Pivotal GemFire 的一种基于配置的便捷注解:@ClientCacheApplication@PerCacheApplication@CacheServerApplication

Pivotal GemFire 支持不同的缓存拓扑,例如客户端/服务器,点对点(p2p)甚至 WAN 准备。在 p2p 中,某一点缓存实例嵌入在应用中,我们的应用将能够以某一点缓存成员的身份参与集群。但是,我们的应用要成为集群中的某一点成员,要手到所有限制,因此,该用法不像客户端/服务器拓扑那样普遍。

在我们的例子中,我们将使用 @ClientCacheApplication 创建一个 “客户端” 缓存实例,该实例具有连接到服务器集群并与之通信的能力。但是,为简单起见,客户端将只使用 LOCAL 客户端区域在本地存储数据,而无需搭建或运行任何服务器。

Spring 推荐生产的企业版 Pivotal GemFire,我们可以在其中跨集群中的多个节点创建分布式缓存和区域。另外,我们也可以使用开源版本 Apache Geode,并从 Apache Geode 社区获得支持。

现在,还记得如何使用 SDG 映射注解 @Region("People") 注解用于存储在 “People” 区域中的 Person 吗?我们可以使用 ClientRegionFactoryBean<String, Person> bean 定义在此定义 Region。我们需要注入刚刚定义的缓存实例,同时将其命名为 “People”

Pivotal GemFire 缓存实例(某一个点或客户端)指示用于存储数据的区域的容器。我们可以将高速缓存视为 RDBMS 中的架构,将区域视为表。但是,缓存还执行其他管理功能来控制和管理我们的所有区域。

类型为 <String, Person>,将键类型(String)与值类型(Perosn)匹配。

public static void main() 方法使用 Spring Boot 的 SpringApplication.run() 启动应用,并调用 ApplicationRunner(另一个 bean 定义),其使用应用的 Spring Data Repository 在 Picotal GemFire 上执行数据访问操作。

该应用会自动关联我们刚定义的 PersonRepository 实例。Spring Data for Pivotal GemFire 将动态创建一个具体类,该类实现该接口并插入所需的查询代码以满足接口的义务。run() 方法使用该 Repository 实例来演示功能。
 

存储并获取数据

该指南中,我们将创建三个本地的 Person 对象,AliceBaby BobTeen Carol。最初,它们仅存在于内存中。创建它们之后,我必须将它们保存到 Pivotal GemFire。

现在,我们运行几个查询。第一个按名称查找每个人。然后,我们将执行一些查询,,以使用年龄属性查找成人、婴儿和青少年。打开日志记录后,我们可以看到 Spring Data for Pivotal GemFire 为我们编写的查询。

@ClientCacheApplication 注解的 logLevel 属性更改为 “config” 以查看由 SDG 生成的 Pivotal GemFire OQL 查询语句。由于查询方法(例如 findByName)已使用 SDG 的 @Trace 注解进行标注,因此将打开 Pivotal GemFire 的 OQL 查询跟踪(查询级别日志记录),从而向我们显示生成的 OQL,执行时间以及查询是否使用了任何 Pivotal GemFire Indexes 来收集结果,以及查询返回的行数。

 

构建可执行 JAR

我们可以结合 Gradle 或 Maven 来从命令行运行该应用。我们还可以构建一个包含所有必须依赖项、类以及资源的可执行 JAR 文件,然后运行该文件。在整个开发生命周期中,跨环境等等情况下,构建可执行 JAR 可以轻松地将服务作为应用进行发布、版本化以及部署。

如果使用 Gradle,则可以借助 ./gradlew bootRun 来运行应用。或通过借助 ./gradlew build 来构建 JAR 文件,然后运行 JAR 文件,如下所示:

java -jar build/libs/gs-accessing-data-gemfire-0.1.0.jar

如果使用 Maven,则可以借助 ./mvnw spring-boot:run 来运行该用。或可以借助 ./mvnw clean package 来构建 JAR 文件,然后运行 JAR 文件,如下所示:

java -jar target/gs-accessing-data-gemfire-0.1.0.jar

我们还可以构建一个经典的 WAR 文件

我们应该看到类似以下的内容(以及其他类似查询语句的内容):

Before linking up with GemFire...
	Alice is 40 years old.
	Baby Bob is 1 years old.
	Teen Carol is 13 years old.
Lookup each person by name...
	Alice is 40 years old.
	Baby Bob is 1 years old.
	Teen Carol is 13 years old.
Adults (over 18):
	Alice is 40 years old.
Babies (less than 5):
	Baby Bob is 1 years old.
Teens (between 12 and 20):
	Teen Carol is 13 years old.

 

概述

恭喜你!我们搭建了 Pivotal GemFire 缓存客户端,存储了简单的实体,并开发了快速查询语句。
 

参见

以下指南也可能会有所帮助:

想看指南的其他内容?请访问该指南的所属专栏:《Spring 官方指南

 类似资料: