我创建了一个带有Geode / GemFire缓存的Spring Boot应用程序。我想用我的Spring Boot应用程序连接到Gfsh创建的Region。在我的application-context.xml
中,我使用的是gfe:lookup-region
,其ID为Gfsh创建的Region。
在我的Java配置文件中,我使用LookupRegionFactoryBean
来获取对外部定义的Region的引用。
在我的SpringBootApplication
引导类中,由于可以读回所有保存的对象,因此我成功地写入了存储库。但是,使用Gfsh工具或Pulse工具时,我看不到缓存的数据记录(或保存的计数)。
您能在这里提供一些见解吗?另外,我也尝试在配置文件中使用LocalRegionFactoryBean
,但是该方法也不起作用。
谢谢。
application-context.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:gfe-data="http://www.springframework.org/schema/data/gemfire"
xmlns:gfe="http://www.springframework.org/schema/gemfire"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/data/gemfire http://www.springframework.org/schema/data/gemfire/spring-data-gemfire.xsd http://www.springframework.org/schema/gemfire http://www.springframework.org/schema/gemfire/spring-gemfire.xsd">
<context:component-scan base-package="com.example.geode"></context:component-scan>
<util:properties id="gemfireProperties" location="context:geode.properties"/>
<!-- <context:property-placeholder location="context:geode.properties"/>
<bean id="log-level"><property name="log-level" value="${log-level}"/></bean>
<bean id="mcast-port"><property name="mcast-port" value="${mcast-port}"/></bean>
<bean id="name"><property name="name" value="${name}"/></bean>-->
<gfe:annotation-driven/>
<gfe-data:function-executions base-package="com.example.geode.config"/>
<!-- Declare GemFire Cache -->
<!-- <gfe:cache/> -->
<gfe:cache properties-ref="gemfireProperties"/>
<!-- Local region for being used by the Message -->
<!-- <gfe:replicated-region id="employee" value-constraint="com.example.geode.model.Employee" data-policy="REPLICATE"/>-->
<gfe:lookup-region id="employee" value-constraint="com.example.geode.model.Employee" data-policy="REPLICATE"/>
<!-- <gfe:local-region id="employee" value-constraint="com.example.geode.model.Employee" data-policy="REPLICATE"/>-->
<!-- Search for GemFire repositories -->
<gfe-data:repositories base-package="com.example.geode.repository"/>
</beans>
GeodeConfiguration.java:
//imports not included
@Configuration
@ComponentScan
@EnableCaching
@EnableGemfireRepositories//(basePackages = "com.example.geode.repository")
@EnableGemfireFunctions
@EnableGemfireFunctionExecutions//(basePackages = "com.example.geode.function")
@PropertySource("classpath:geode.properties")
public class GeodeConfiguration {
@Autowired
private EmployeeRepository employeeRepository;
@Autowired
private FunctionExecution functionExecution;
@Value("${log-level}")
private String loglevel;
@Value("${mcast-port}")
private String mcastPort;
@Value("${name}")
private String name;
Properties gemfireProperties() {
Properties gemfireProperties = new Properties();
gemfireProperties.setProperty(loglevel, loglevel);
gemfireProperties.setProperty(mcastPort, mcastPort);
gemfireProperties.setProperty(name, name);
return gemfireProperties;
}
@Bean
CacheFactoryBean gemfireCache() {
return new CacheFactoryBean();
}
@Bean
GemfireCacheManager cacheManager() {
GemfireCacheManager cacheManager = new GemfireCacheManager();
try {
CacheFactoryBean cacheFactory = gemfireCache();
//gemfireProperties();
//cacheFactory.setProperties(gemfireProperties());
cacheManager.setCache(cacheFactory.getObject()); //gemfireCache().getObject());
} catch (Exception ex) {
ex.printStackTrace();
}
return cacheManager;
}
@Bean(name="employee")
//@Autowired
LookupRegionFactoryBean<String, Employee> getRegion(final GemFireCache cache)
throws Exception {
//CacheTypeAwareRegionFactoryBean<String, Employee> region = new CacheTypeAwareRegionFactoryBean<>();//GenericRegionFactoryBean<> //LocalRegionFactoryBean<>();
LookupRegionFactoryBean<String, Employee> region = new LookupRegionFactoryBean<>();//GenericRegionFactoryBean<> //LocalRegionFactoryBean<>();
region.setRegionName("employee");
try {
region.setCache(gemfireCache().getObject());
} catch (Exception e) {
e.printStackTrace();
}
//region.setClose(false);
region.setName("employee");
//region.setAsyncEventQueues(new AsyncEventQueue[]{gemfireQueue});
//region.setPersistent(false);
//region.setDataPolicy(org.apache.geode.cache.DataPolicy.REPLICATE); //PRELOADED); //REPLICATE);
region.afterPropertiesSet();
return region;
}
}
BasicGeodeApplication.java:
//imports not provided
@EnableGemfireRepositories
@SpringBootApplication
@ComponentScan("com.example.geode")
//@EnableCaching
@EnableGemfireCaching
@EnableEntityDefinedRegions(basePackageClasses = Employee.class)
@SuppressWarnings("unused")
//@CacheServerApplication(name = "server2", locators = "localhost[10334]",
// autoStartup = true, port = 41414)
public class BasicGeodeApplication {
@Autowired
private EmployeeRepository employeeRepository;
@Autowired
private EmployeeService employeeService;
private static ConfigurableApplicationContext context;
public static void main(String[] args) {
context = SpringApplication.run(BasicGeodeApplication.class, args);
BasicGeodeApplication bga = new BasicGeodeApplication();
}
@Bean
public ApplicationRunner run(EmployeeRepository employeeRepository) {
return args -> {
Employee bob = new Employee("Bob", 80.0);
Employee sue = new Employee("Susan", 95.0);
Employee jane = new Employee("Jane", 85.0);
Employee jack = new Employee("Jack", 90.0);
List<Employee> employees = Arrays.asList(bob, sue, jane, jack);
employees.sort(Comparator.comparing(Employee::getName));
for (Employee employee : employees) {
//employeeService.saveEmployee(employee);
employeeRepository.save(employee);
}
System.out.println("\nList of employees:");
employees //Arrays.asList(bob.getName(), sue.getName(), jane.getName(), jack.getName());
.forEach(person -> System.out.println("\t" + employeeRepository.findByName(person.getName())));
System.out.println("\nQuery salary greater than 80k:");
stream(employeeRepository.findBySalaryGreaterThan(80.0).spliterator(), false)
.forEach(person -> System.out.println("\t" + person));
System.out.println("\nQuery salary less than 95k:");
stream(employeeRepository.findBySalaryLessThan(95.0).spliterator(), false)
.forEach(person -> System.out.println("\t" + person));
System.out.println("\nQuery salary greater than 80k and less than 95k:");
stream(employeeRepository.findBySalaryGreaterThanAndSalaryLessThan(80.0, 95.0).spliterator(), false)
.forEach(person -> System.out.println("\t" + person));
};
}
@Service
class EmployeeService {
@Autowired
private EmployeeRepository employeeRepository;
@CachePut(cacheNames = "employee", key = "#id")
//@PutMapping("/")
void saveEmployee(Employee employee) {
employeeRepository.save(employee);
}
Employee findEmployee(String name) {
return null;
}
//employeeRepository.findByName(person.getName())));
}
}
EmployeeRepository.java:
@Repository("employeeRepository")
//@DependsOn("gemfireCache")
public interface EmployeeRepository extends CrudRepository<Employee, String> {
Employee findByName(String name);
Iterable<Employee> findBySalaryGreaterThan(double salary);
Iterable<Employee> findBySalaryLessThan(double salary);
Iterable<Employee> findBySalaryGreaterThanAndSalaryLessThan(double salary1, double salary2);
}
Employee.java:
// imports not included
@Entity
@Region("employee")
public class Employee implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
@javax.persistence.Id
private Long id;
public String name;
public double salary;
protected Employee() {}
@PersistenceConstructor
public Employee(String name, double salary) {
this.name = name;
this.salary = salary;
}
@Override
public String toString() {
return name + " salary is: " + salary;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getSalary() {
return salary;
}
public void setSalary(int salary) {
this.salary = salary;
}
}
答案 0 :(得分:2)
如果您的Spring Boot应用程序实际上使用了在尝试查找后在Gfsh中创建的Region,我会感到非常惊讶。从以下事实也可以明显看出这一点:在运行应用程序后使用 Gfsh 或 Pulse 时,您无法在Region中看到数据。
此外,由于您尚未共享geode.properties
文件的内容,因此从您的配置中并不能完全清楚Spring Boot应用程序是否要加入以 Gfsh 开头的集群。 / p>
注意:由于您如何引用属性文件,因此我们将稍后返回您的属性文件(例如,在Spring {的
context:
元素的location
属性中使用<util>
{1}}模式)甚至都不正确。实际上,您的整个XML文件甚至无效!除非抽象,否则没有Util
的Bean定义将无效。
您正在使用哪个版本的Spring Boot和Spring Data Geode / GemFire(SDG)?
从XML配置文件中的Spring XML模式引用来看,您正在使用Spring 3.0!您不应在架构位置声明中引用版本。不合格的架构版本将根据您在应用程序类路径上导入的Spring JAR(例如,使用Maven)进行版本控制。
无论如何,我想问的原因是,我对SDG进行了许多更改,导致在配置不明确或不完整的情况下(对于instance,它会快速失败)。
在您的情况下,如果地区不存在,查找将立即失败。而且,我可以肯定不存在Region(一个或多个),因为默认情况下,对等缓存节点/应用程序上的SDG disables Cluster Configuration。因此,您在 Gfsh 中创建的Region都不可立即用于您的Spring Boot应用程序。
因此,让我们来看一个简单的例子。我将主要使用SDG的新annotation configuration model并结合一些Java配置,以易于使用和方便。鉴于您的配置无处不在,我鼓励您阅读SDG参考指南中的这一章,并且我可以肯定的是,您确实混淆了正在发生的事情。
这是我的Spring Boot,Apache Geode应用程序...
class
我正在使用 Spring数据 @SpringBootApplication
@SuppressWarnings("unused")
public class ClusterConfiguredGeodeServerApplication {
public static void main(String[] args) {
SpringApplication.run(ClusterConfiguredGeodeServerApplication.class, args);
}
@Bean
ApplicationRunner runner(GemfireTemplate customersTemplate) {
return args -> {
Customer jonDoe = Customer.named("Jon Doe").identifiedBy(1L);
customersTemplate.put(jonDoe.getId(), jonDoe);
};
}
@PeerCacheApplication(name = "ClusterConfiguredGeodeServerApplication")
@EnablePdx
static class GeodeConfiguration {
@Bean("Customers")
LookupRegionFactoryBean<Long, Customer> customersRegion(GemFireCache gemfireCache) {
LookupRegionFactoryBean<Long, Customer> customersRegion = new LookupRegionFactoryBean<>();
customersRegion.setCache(gemfireCache);
return customersRegion;
}
@Bean("CustomersTemplate")
GemfireTemplate customersTemplate(@Qualifier("Customers") Region<?, ?> customers) {
return new GemfireTemplate(customers);
}
}
@Data
@RequiredArgsConstructor(staticName = "named")
static class Customer {
@Id
private Long id;
@NonNull
private String name;
Customer identifiedBy(Long id) {
this.id = id;
return this;
}
}
}
(其中包括 Apache Geode的 Spring数据 Lovelace RC1
)。我还使用了Spring Boot 2.1.0.RC1
,它引入了核心Spring Framework 2.0.3.RELEASE
,全部基于Java 8。
我省略了包装和进口声明。
我正在使用Project Lombok定义我的5.0.7.RELEASE
类。
我有一个嵌套的Customer
类,用于将Spring Boot应用程序配置为能够加入Apache Geode集群的“对等” GeodeConfiguration
成员。但是,它还不属于任何群集!
最后,我配置了一个“客户”区域,该区域在Spring上下文中被“查找”。
启动此应用程序时,它失败了,因为无论如何都没有定义“客户”区域...
Cache
这是预期的!
好的,让我们进入 Gfsh 并启动一个集群。
您知道您需要使用服务器启动定位器以形成集群,对吗?定位器由试图加入群集的其他潜在对等方使用,以便他们可以首先定位群集。由于无法在定位器上创建区域,因此需要服务器才能创建“客户”区域。
Caused by: org.springframework.beans.factory.BeanInitializationException: Region [Customers] in Cache [GemFireCache[id = 2126876651; isClosing = false; isShutDownAll = false; created = Thu Aug 02 13:43:07 PDT 2018; server = false; copyOnRead = false; lockLease = 120; lockTimeout = 60]] not found
at org.springframework.data.gemfire.ResolvableRegionFactoryBean.createRegion(ResolvableRegionFactoryBean.java:146) ~[spring-data-geode-2.1.0.RC1.jar:2.1.0.RC1]
at org.springframework.data.gemfire.ResolvableRegionFactoryBean.afterPropertiesSet(ResolvableRegionFactoryBean.java:96) ~[spring-data-geode-2.1.0.RC1.jar:2.1.0.RC1]
at org.springframework.data.gemfire.LookupRegionFactoryBean.afterPropertiesSet(LookupRegionFactoryBean.java:72) ~[spring-data-geode-2.1.0.RC1.jar:2.1.0.RC1]
...
现在,即使我再次运行Spring Boot应用程序,它仍然会因相同的异常而失败...
$ echo $GEODE_HOME
/Users/jblum/pivdev/apache-geode-1.6.0
$ gfsh
_________________________ __
/ _____/ ______/ ______/ /____/ /
/ / __/ /___ /_____ / _____ /
/ /__/ / ____/ _____/ / / / /
/______/_/ /______/_/ /_/ 1.6.0
Monitor and Manage Apache Geode
gfsh>start locator --name=LocaorOne --log-level=config
Starting a Geode Locator in /Users/jblum/pivdev/lab/LocaorOne...
....
Locator in /Users/jblum/pivdev/lab/LocaorOne on 10.0.0.121[10334] as LocaorOne is currently online.
Process ID: 41758
Uptime: 5 seconds
Geode Version: 1.6.0
Java Version: 1.8.0_152
Log File: /Users/jblum/pivdev/lab/LocaorOne/LocaorOne.log
JVM Arguments: -Dgemfire.enable-cluster-configuration=true -Dgemfire.load-cluster-configuration-from-dir=false -Dgemfire.log-level=config -Dgemfire.launcher.registerSignalHandlers=true -Djava.awt.headless=true -Dsun.rmi.dgc.server.gcInterval=9223372036854775806
Class-Path: /Users/jblum/pivdev/apache-geode-1.6.0/lib/geode-core-1.6.0.jar:/Users/jblum/pivdev/apache-geode-1.6.0/lib/geode-dependencies.jar
Successfully connected to: JMX Manager [host=10.0.0.121, port=1099]
Cluster configuration service is up and running.
gfsh>start server --name=ServerOne --log-level=config
Starting a Geode Server in /Users/jblum/pivdev/lab/ServerOne...
...
Server in /Users/jblum/pivdev/lab/ServerOne on 10.0.0.121[40404] as ServerOne is currently online.
Process ID: 41785
Uptime: 3 seconds
Geode Version: 1.6.0
Java Version: 1.8.0_152
Log File: /Users/jblum/pivdev/lab/ServerOne/ServerOne.log
JVM Arguments: -Dgemfire.default.locators=10.0.0.121[10334] -Dgemfire.start-dev-rest-api=false -Dgemfire.use-cluster-configuration=true -Dgemfire.log-level=config -XX:OnOutOfMemoryError=kill -KILL %p -Dgemfire.launcher.registerSignalHandlers=true -Djava.awt.headless=true -Dsun.rmi.dgc.server.gcInterval=9223372036854775806
Class-Path: /Users/jblum/pivdev/apache-geode-1.6.0/lib/geode-core-1.6.0.jar:/Users/jblum/pivdev/apache-geode-1.6.0/lib/geode-dependencies.jar
gfsh>list members
Name | Id
--------- | --------------------------------------------------------------
LocaorOne | 10.0.0.121(LocaorOne:41758:locator)<ec><v0>:1024 [Coordinator]
ServerOne | 10.0.0.121(ServerOne:41785)<v1>:1025
gfsh>list regions
No Regions Found
gfsh>create region --name=Customers --type=PARTITION --key-constraint=java.lang.Long --value-constraint=java.lang.Object
Member | Status
--------- | ------------------------------------------
ServerOne | Region "/Customers" created on "ServerOne"
gfsh>list regions
List of regions
---------------
Customers
gfsh>describe region --name=Customers
..........................................................
Name : Customers
Data Policy : partition
Hosting Members : ServerOne
Non-Default Attributes Shared By Hosting Members
Type | Name | Value
------ | ----------- | ---------
Region | size | 0
| data-policy | PARTITION
为什么?
这是因为1)Spring Boot Apache Geode对等体Caused by: org.springframework.beans.factory.BeanInitializationException: Region [Customers] in Cache [GemFireCache[id = 989520513; isClosing = false; isShutDownAll = false; created = Thu Aug 02 14:09:25 PDT 2018; server = false; copyOnRead = false; lockLease = 120; lockTimeout = 60]] not found
at org.springframework.data.gemfire.ResolvableRegionFactoryBean.createRegion(ResolvableRegionFactoryBean.java:146) ~[spring-data-geode-2.1.0.RC1.jar:2.1.0.RC1]
at org.springframework.data.gemfire.ResolvableRegionFactoryBean.afterPropertiesSet(ResolvableRegionFactoryBean.java:96) ~[spring-data-geode-2.1.0.RC1.jar:2.1.0.RC1]
at org.springframework.data.gemfire.LookupRegionFactoryBean.afterPropertiesSet(LookupRegionFactoryBean.java:72) ~[spring-data-geode-2.1.0.RC1.jar:2.1.0.RC1]
...
应用程序尚未包含在集群中; 2)默认情况下,SDG不允许Spring配置/引导的Apache Geode对等体{ {1}}应用程序才能从群集(特别是Cluster Configuration Service)获得配置,因此,我们必须同时配置/启用这两项。
我们可以通过将Cache
批注的Cache
属性指定为Cache
来使Spring Boot,Apache Geode对等locators
应用程序加入集群。
@PeerCacheApplication
我们可以让我们的Spring Boot Apache Geode对等localhost[10334]
应用程序通过启用@PeerCacheApplication(name = "...", locators = "localhost[10334]")
属性从集群中获取其配置,这是通过将以下Cache
bean定义添加到我们的内部静态useClusterConfiguration
类,如下所示:
Configurer
现在,当我们再次运行我们的Spring Boot,Apache Geode对等GeodeConfiguration
应用程序时,我们将看到完全不同的输出。首先,看到我们的对等成员(应用程序)获得了集群配置...
@Bean
PeerCacheConfigurer useClusterConfigurationConfigurer() {
return (beanName, cacheFactoryBean) -> cacheFactoryBean.setUseClusterConfiguration(true);
}
接下来,您可能已经注意到,我使用SDG的Cache
注释启用了PDX。这使我们可以轻松地序列化我们的应用程序域模型对象类型(例如<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<cache xmlns="http://geode.apache.org/schema/cache" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" copy-on-read="false" is-server="false" lock-lease="120" lock-timeout="60" search-timeout="300" version="1.0" xsi:schemaLocation="http://geode.apache.org/schema/cache http://geode.apache.org/schema/cache/cache-1.0.xsd">
<region name="Customers">
<region-attributes data-policy="partition">
<key-constraint>java.lang.Long</key-constraint>
<value-constraint>java.lang.Object</value-constraint>
</region-attributes>
</region>
</cache>
),而我们的类型不需要过度实现@EnablePdx
。有几个原因导致您不一定要实现Customer
。使用SDG的java.io.Serializable
使用SDG的MappingPdxSerializer
实现,甚至比Apache Geode / Pivotal GemFire自己的java.io.Serializable
更强大。
序列化应用程序类型(即@EnablePdx
)的结果是,您将看到此输出...
ReflectionBasedAutoSerializer
启用PDX的另一个原因是,我不需要将Customer
类添加到使用 Gfsh 开始的服务器(即“ 14:26:48.322 [main] INFO org.apache.geode.internal.cache.PartitionedRegion - Partitioned Region /Customers is created with prId=2
Started ClusterConfiguredGeodeServerApplication in 4.223 seconds (JVM running for 5.574)
14:26:48.966 [main] INFO org.apache.geode.pdx.internal.PeerTypeRegistration - Adding new type: PdxType[dsid=0, typenum=14762571
name=example.app.spring.cluster_config.server.ClusterConfiguredGeodeServerApplication$Customer
fields=[
id:Object:identity:0:idx0(relativeOffset)=0:idx1(vlfOffsetIndex)=-1
name:String:1:1:idx0(relativeOffset)=0:idx1(vlfOffsetIndex)=1]]
14:26:49.002 [main] INFO org.apache.geode.pdx.internal.TypeRegistry - Caching PdxType[dsid=0, typenum=14762571
name=example.app.spring.cluster_config.server.ClusterConfiguredGeodeServerApplication$Customer
fields=[
id:Object:identity:0:idx0(relativeOffset)=0:idx1(vlfOffsetIndex)=-1
name:String:1:1:idx0(relativeOffset)=0:idx1(vlfOffsetIndex)=1]]
”)中。它还使我可以查询“客户”区域,并看到成功添加了Customer
“乔恩·多伊” ...
ServerOne
宾果!成功!
我什至不会开始讨论您的配置有问题的所有内容。我恳请您read the docs(和Apache Geode的User Guide;即相应的部分),理解概念,查看examples,guides,提出简洁的问题等。
这是示例源代码...
希望这会有所帮助!
-j