本指南将引导您完成使用Pivotal GemFire的数据结构构建应用程序的过程。您将使用为Pivotal GemFire提供的强大Spring Data库来存储和检索POJO。

程序结构

└── 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.1.6.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</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将会你做如下的事:

  • 将 classpath 里面所有用到的jar包构建成一个可执行的 JAR 文件,方便执行你的程序
  • 搜索public static void main()方法并且将它当作可执行类
  • 根据springboot版本,去查找相应的依赖类版本,当然你可以定义其它版本。

定义一个简单实体

Pivotal GemFire是一个内存数据网格(IMDG),它将数据映射到区域。可以在集群中配置跨多个节点分区和复制数据的分布式区域。但是,在本指南中,您将使用本地区域,因此不必设置任何额外的内容,例如整个服务器集群。

Pivotal GemFire是一个Key/Value存储,一个区域类Region实现了java.util.concurrent.concurrentmap接口。虽然您可以像java.util.Map那样对待一个区域,但它比简单的Java映射更复杂一些,因为给定的数据在该区域内被分发、复制和其它一般管理。
在本例中,只使用少数注释将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类。在创建新实例时,您还拥有一个持久的构造函数来填充实体。该类使用Lombok项目来简化实现。
注意,这个类是用@Region("People")注释的。当Pivotal GemFire存储此类的实例时,将在“People”区域内创建一个新条目。此类还用@Id标记名称字段。这表示用于标识和跟踪Pivotal GemFire中人员数据的标识符。本质上,@Id注释字段(例如name)是键,person实例是key/value的value。在Pivotal GemFire中没有自动生成key,因此必须在将实体持久化为Pivotal GemFire之前设置ID(即名称)。
下一个重要的部分是人的年龄。在本指南的后面部分,您将使用它来设计一些查询。
重写的toString()方法将打印出此人的姓名和年龄。

创建简单查询
Pivotal GemFire的Spring Data聚焦于使用Spring在GemFire中存储和访问数据。它还继承了Spring Data Commons项目的强大功能,例如派生查询的能力。本质上,您不必学习Pivotal GemFire (OQL)的查询语言;您可以简单地编写一些方法,这些查询是由框架为您编写的。
要了解这是如何工作的,请创建一个查询存储在Pivotal 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接口,并为存储库分别使用的value和ID(key),即Person和String,指定了通用类型参数的类型。该接口提供了许多操作,可以开箱即用,包括基本CRUD(创建、读取、更新、删除)和简单查询(例如 findById(..))数据访问操作。
您可以根据需要定义其他查询,只需声明它们的方法签名。在本例中,添加findByName,它基本上搜索person类型的对象,并找到一个与name匹配的对象。
你还可以:
findByAgeGreaterThan 查找大于几岁的人
findByAgeLessThan 查找小于几岁的人
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));
        };
    }
}

在配置中,您需要添加@EnableGemFireStores注释。
默认情况下,@EnableGemFireRepository将扫描当前包中任何扩展Spring Data’s Repository的接口。使用它的basePackageClasses = MyRepository.class安全地告诉 Pivotal GemFire的Spring Data,以便按类型扫描不同的根包以获得特定于应用程序的存储库扩展。
Pivotal GemFire缓存需要包含1个或多个区域来存储所有数据。为此,您可以使用1个Spring Data作为Pivotal GemFire的基于配置的注释:@ClientCacheApplication, @PeerCacheApplication或@CacheServerApplication.
Pivotal GemFire支持不同的缓存拓扑,如客户端/服务器、端对端(P2P)甚至广域网模式。在p2p模式中,端点缓存实例嵌入到应用程序中,应用程序将能够作为对等缓存成员参与集群。但是,您的应用程序受到集群的约束,因此这不像客户机/服务器拓扑结构那样常用。
在我们的例子中,我们将使用@ClientCacheApplication创建一个“客户机”缓存实例,该实例能够连接到服务器集群并与之通信。但是,为了简单起见,客户机将只使用本地客户机区域在本地存储数据,而不需要设置或运行任何服务器。

Spring推荐使用GemFire企业版,在这里您可以跨集群中的多个节点创建分布式缓存和区域。或者,您也可以使用开源版本Apache Geode,并从Apache Geode社区获得支持。
现在,还记得如何使用SDG 映射注释,@Region("People"),把Person标记在名为“Person”的区域中?您 可以使用ClientRegionFactoryBean<String, Person>bean定义该区域。您需要插入刚刚定义的缓存实例,同时将其命名为“People”。

Pivotal GemFire缓存实例(无论是端对端还是客户机)只是存储数据的区域的容器。您可以将缓存视为RDBMS中的schema,将区域视为表。但是,缓存还执行其他管理功能来控制和管理所有区域。

类型为<string,person>,将key类型(String)与VALUE类型(Person)匹配。
应用程序自动连接刚刚定义的PersonRepository实例。Pivotal GemFire的Spring Data将动态创建实现此接口的具体类,并插入所需的查询代码以满足接口的义务。run()方法使用此存储库实例来演示功能。

存储和获取数据
在本指南中,您将创建三个本地Person o对象:Alice、Baby Bob和Teen Carol。最初,它们只存在于内存中。在创建它们之后,您必须将它们保存到Pivotal GemFire。
在本指南中,您将创建三个本地人对象:Alice、Baby Bob和Teen Carol。最初,它们只存在于内存中。在创建它们之后,您必须将它们保存到关键的gemfire。
现在运行几个查询。第一个按名字查找每个人。然后,您执行一些查询来查找成年人、婴儿和青少年,所有这些都使用年龄属性。打开日志后,你会看到相关的日志。

将@ClientCacheApplication注解的日志级另属性更改为“config”,以查看由SDG生成的GemFire OQL查询。因为查询方法(例如findByName)是用SDG的@Trace注释进行注释的,所以这将打开Pivotal GemFire的OQL查询跟踪(查询级别日志记录),其中显示生成的OQL、执行时间、查询是否使用任何Pivotal GemFire索引来收集结果以及查询返回的行数。

执行程序
您应该看到类似这样的内容(以及查询等其他内容):

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.

祝贺你!您设置了一个GemFire缓存客户端,存储了简单的实体,并开发了快速查询。