本指南将引导您完成使用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缓存客户端,存储了简单的实体,并开发了快速查询。