首页 > 其他分享 >Apache Geode 的 Spring Data(数据)(四)

Apache Geode 的 Spring Data(数据)(四)

时间:2022-11-22 18:38:43浏览次数:69  
标签:String Spring Geode Apache org 属性

Apache Geode 的 Spring Data(数据)(四)_xml

7.5. 使用@TransactionalEventListener

使用事务时,可能需要注册侦听器以在 事务提交,或在发生回滚后。

Spring Data for Apache Geode 可以轻松创建侦听器,这些侦听器将在带有注释的事务的特定阶段被调用。注释的方法(如下所示)将是 在指定的期间通知从事务方法发布的事件。​​@TransactionalEventListener​​​​@TransactionalEventListener​​​​phase​

事务提交后事件侦听器

@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
public void handleAfterCommit(MyEvent event) {
// do something after transaction is committed
}

为了调用上述方法,您必须从事务中发布事件,如下所示:

发布事务性事件

@Service
class MyTransactionalService {

@Autowired
private final ApplicationEventPublisher applicationEventPublisher;

@Transactional
public <Return-Type> someTransactionalServiceMethod() {

// Perform business logic interacting with and accessing multiple transactional resources atomically, then...

applicationEventPublisher.publishEvent(new MyApplicationEvent(...));
}

...
}

注释允许您指定事件处理程序在其中的事务 方法将被调用。选项包括:,,,和。 如果未指定,则默认为 。如果您希望在没有事务时调用侦听器 存在,您可以设置。​​@TransactionalEventListener​​​​phase​​​​AFTER_COMMIT​​​​AFTER_COMPLETION​​​​AFTER_ROLLBACK​​​​BEFORE_COMMIT​​​​phase​​​​AFTER_COMMIT​​​​fallbackExecution​​​​true​

7.6. 自动交易事件发布

从 Apache Geode 的 Spring Data 开始,现在可以启用自动事务事件发布。​​Neumann/2.3​

使用注释,设置属性 到。默认值为false。​​@EnableGemfireCacheTransactions​​​​enableAutoTransactionEventPublishing​

启用自动事务事件发布

@EnableGemfireCacheTransactions(enableAutoTransactionEventPublishing = true)
class GeodeConfiguration { ... }

然后,您可以创建带注释的 POJO 方法来处理任一期间的事务事件 理论事务阶段。​​@TransactionalEventListener​​​​AFTER_COMMIT​​​​AFTER_ROLLBACK​

@Component
class TransactionEventListeners {

@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
public void handleAfterCommit(TransactionApplicationEvent event) {
...
}

@TransactionalEventListener(phase = TransactionPhase.AFTER_ROLLBACK)
public void handleAfterRollback(TransactionApplicationEvent event) {
...
}
}


Onlyandare supported.is 不支持,因为 1) SDG 调整 Apache Geode 的 sandinterfaces 来实现自动事务事件发布,以及 2) 当调用 Apache Geode 时,它已经在调用之后,其中注释的 POJO 方法在事务生命周期中被调用。​​TransactionPhase.AFTER_COMMIT​​​​TransactionPhase.AFTER_ROLLBACK​​​​TransactionPhase.BEFORE_COMMIT​​​​TransactionListener​​​​TransactionWriter​​​​TransactionWriter.beforeCommit(:TransactionEvent)​​​​AbstractPlatformTransactionManager.triggerBeforeCommit(:TransactionStatus)​​​​@TranactionalEventListener​

使用自动事务事件发布,无需在应用程序方法中显式调用该方法。​​applicationEventPublisher.publishEvent(..)​​​​@Transactional​​​​@Service​

但是,如果您仍然希望“在提交之前”接收事务事件,那么您仍然必须在应用程序方法中调用该方法。 有关更多详细信息,请参阅上面的注释。​​applicationEventPublisher.publishEvent(..)​​​​@Transactional​​​​@Service​

7.7. 连续查询

Apache Geode提供的强大功能是​​Continuous Query​​(或CQ)。

简而言之,CQ允许开发人员创建和注册OQL查询,然后在新数据时自动收到通知 添加到 Apache Geode 匹配查询谓词。Spring Data for Apache Geode 提供专用 通过包及其侦听器容器支持 CQ; 在功能和命名上与Spring 框架中的 JMS 集成非常相似;事实上,熟悉的用户 春季的JMS支持,应该有宾至如归的感觉。​​org.springframework.data.gemfire.listener​

基本上,Apache Geode的Spring Data允许POJO上的方法成为CQ的端点。只需定义查询 并指示在存在匹配项时应调用以通知的方法。春季数据为Apache Geode照顾 其余的。这与Java EE的消息驱动Bean风格非常相似,但对基类没有任何要求。 或基于 Apache Geode 的接口实现。

目前,连续查询仅在 Apache Geode 的客户端/服务器拓扑中受支持。此外,客户端池 需要“已使用”才能启用订阅。有关更多信息,请参阅 Apache Geode文档。

7.7.1. 连续查询侦听器容器

Spring Data for Apache Geode 通过处理 围绕CQ的基础设施,使用SDG,完成所有繁重的工作 代表用户。熟悉 EJB 和 JMS 的用户应该在设计时发现熟悉的概念 尽可能接近Spring 框架中提供的支持及其消息驱动的 POJO (MDP)。​​ContinuousQueryListenerContainer​

SDG 充当事件(或消息)侦听器容器;它用于 从已注册的 CQ 接收事件并调用注入其中的 POJO。侦听器容器 负责消息接收的所有线程处理,并调度到侦听器进行处理。它充当 EDP(事件驱动的POJO)和事件提供者之间的中介,负责创建和注册 CQ(接收事件)、资源获取和释放、异常转换等。这使您可以, 作为应用程序开发人员,编写与接收事件关联的(可能复杂的)业务逻辑 (并对此做出反应),并将样板 Apache Geode 基础结构问题委托给框架。​​ContinuousQueryListenerContainer​

侦听器容器是完全可自定义的。开发人员可以选择使用 CQ 线程来执行调度 (同步交付)或通过定义合适的(或 Spring 的)来异步方法的新线程(来自现有池)。根据负载、侦听器数量 或运行时环境,开发人员应更改或调整执行器以更好地满足其需求。特别 在托管环境(如应用服务器)中,强烈建议选择适当的环境以利用其运行时。​​java.util.concurrent.Executor​​​​TaskExecutor​​​​TaskExecutor​

7.7.2. 和​​ContinuousQueryListener​​​​ContinuousQueryListenerAdapter​

Theclass 是 Spring Data 中用于 Apache Geode CQ 支持的最后一个组件。简而言之 类允许您以最少的约束将几乎任何实现类公开为 EDP。实现接口,一个简单的侦听器接口 类似于Apache Geode的CqListener。​​ContinuousQueryListenerAdapter​​​​ContinuousQueryListenerAdapter​​​​ContinuousQueryListener​

请考虑以下接口定义。请注意各种事件处理方法及其参数:

public interface EventDelegate {
void handleEvent(CqEvent event);
void handleEvent(Operation baseOp);
void handleEvent(Object key);
void handleEvent(Object key, Object newValue);
void handleEvent(Throwable throwable);
void handleQuery(CqQuery cq);
void handleEvent(CqEvent event, Operation baseOp, byte[] deltaValue);
void handleEvent(CqEvent event, Operation baseOp, Operation queryOp, Object key, Object newValue);
}
package example;

class DefaultEventDelegate implements EventDelegate {
// implementation elided for clarity...
}

特别是,请注意上述接口实现根本没有ApacheGeode依赖项。 它确实是一个POJO,我们可以并且将通过以下配置将其制作成EDP。​​EventDelegate​

该类不必实现接口;接口仅用于更好地展示解耦 在合同和实现之间。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:gfe="https://www.springframework.org/schema/geode"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
https://www.springframework.org/schema/geode https://www.springframework.org/schema/geode/spring-geode.xsd
">

<gfe:client-cache/>

<gfe:pool subscription-enabled="true">
<gfe:server host="localhost" port="40404"/>
</gfe:pool>

<gfe:cq-listener-container>
<!-- default handle method -->
<gfe:listener ref="listener" query="SELECT * FROM /SomeRegion"/>
<gfe:listener ref="another-listener" query="SELECT * FROM /AnotherRegion" name="myQuery" method="handleQuery"/>
</gfe:cq-listener-container>

<bean id="listener" class="example.DefaultMessageDelegate"/>
<bean id="another-listener" class="example.DefaultMessageDelegate"/>
...
<beans>

上面的示例显示了侦听器可以具有的一些各种形式;至少,侦听器 引用和实际查询定义是必需的。但是,可以指定 生成的连续查询(对监视有用),还包括方法的名称(默认值为)。 指定的方法可以具有各种参数类型,接口列出了允许的类型。​​handleEvent​​​​EventDelegate​

上面的示例使用 Spring Data for Apache Geode 命名空间来声明事件侦听器容器 并自动注册侦听器。完整的吹定义如下所示:

<!-- this is the Event Driven POJO (MDP) -->
<bean id="eventListener" class="org.springframework.data.gemfire.listener.adapter.ContinuousQueryListenerAdapter">
<constructor-arg>
<bean class="gemfireexample.DefaultEventDelegate"/>
</constructor-arg>
</bean>

<!-- and this is the event listener container... -->
<bean id="gemfireListenerContainer" class="org.springframework.data.gemfire.listener.ContinuousQueryListenerContainer">
<property name="cache" ref="gemfireCache"/>
<property name="queryListeners">
<!-- set of CQ listeners -->
<set>
<bean class="org.springframework.data.gemfire.listener.ContinuousQueryDefinition" >
<constructor-arg value="SELECT * FROM /SomeRegion" />
<constructor-arg ref="eventListener"/>
</bean>
</set>
</property>
</bean>

每次收到事件时,适配器都会自动在 Apache Geode 事件之间执行类型转换 和所需的方法参数透明地。捕获由方法调用导致的任何异常 并由容器处理(默认情况下,被记录)。

7.8. 接线组件​​Declarable​

Apache Geode XML配置(通常称为)允许用户对象被声明 作为配置的一部分。通常这些对象是或其他可插拔的回调组件 由Apache Geode支持。使用本机 Apache Geode 配置,通过 XML 声明的每个用户类型都必须实现 接口,允许将任意参数传递给声明的类 通过实例。​​cache.xml​​​​CacheLoaders​​​​Declarable​​​​Properties​

在本节中,我们将介绍如何在使用 Spring 中定义时配置这些可插拔组件,同时保持缓存/区域配置的定义。这允许您 可插拔组件,用于关注应用程序逻辑,而不是位置或创建 o对于其他协作者。​​cache.xml​​​​cache.xml​​​​DataSources​

但是,如果要启动绿地项目,建议您配置缓存、区域、 和其他可插拔的 Apache Geode 组件直接在 Spring 中。这避免了从接口继承 或本节中介绍的基类。​​Declarable​

有关此方法的详细信息,请参阅以下侧边栏。

消除组件​​Declarable​

开发人员可以完全通过 Spring 配置自定义类型,如配置区域中所述。 这样,开发人员就不必实现接口,并且还可以从 Spring IoC容器的所有功能(不仅是依赖注入,还有生命周期) 和实例管理)。​​Declarable​

作为使用 Spring 配置组件的示例,请考虑以下声明 (摘自Javadoc):​​Declarable​​​​Declarable​

<cache-loader>
<class-name>com.company.app.DBLoader</class-name>
<parameter name="URL">
<string>jdbc://12.34.56.78/mydb</string>
</parameter>
</cache-loader>

为了简化解析,转换参数和初始化对象的任务,Spring Data for Apache Geode提供了 一个基类 (),它允许通过模板Bean 定义连接 Apache Geode 用户对象 或者,如果缺少,请通过Spring IoC容器执行自动接线。要利用此功能, 用户对象需要扩展,它会自动定位声明并在初始化过程中执行连接。​​WiringDeclarableSupport​​​​WiringDeclarableSupport​​​​BeanFactory​

为什么需要基类?

在当前的 Apache Geode 版本中,没有对象工厂的概念,并且声明的类型被实例化 并按原样使用。换句话说,在Apache Geode之外管理对象创建没有简单的方法。

7.8.1. 使用模板Bean 定义进行配置

使用时,尝试首先找到现有的 Bean 定义并使用它 作为布线模板。除非指定,否则组件类名将用作隐式 Bean 定义名。​​WiringDeclarableSupport​

让我们看看在这种情况下我们的声明会是什么样子:​​DBLoader​

class DBLoader extends WiringDeclarableSupport implements CacheLoader {

private DataSource dataSource;

public void setDataSource(DataSource dataSource){
this.dataSource = dataSource;
}

public Object load(LoaderHelper helper) { ... }
}
<cache-loader>
<class-name>com.company.app.DBLoader</class-name>
<!-- no parameter is passed (use the bean's implicit name, which is the class name) -->
</cache-loader>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
">

<bean id="dataSource" ... />

<!-- template bean definition -->
<bean id="com.company.app.DBLoader" abstract="true" p:dataSource-ref="dataSource"/>
</beans>

在上面的场景中,由于没有指定参数,因此使用了具有 id/name 的 bean 作为连接由 Apache Geode 创建的实例的模板。对于 Bean 名称使用不同约定的情况, 可以在 Apache Geode 配置中传入参数:​​com.company.app.DBLoader​​​​bean-name​

<cache-loader>
<class-name>com.company.app.DBLoader</class-name>
<!-- pass the bean definition template name as parameter -->
<parameter name="bean-name">
<string>template-bean</string>
</parameter>
</cache-loader>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
">

<bean id="dataSource" ... />

<!-- template bean definition -->
<bean id="template-bean" abstract="true" p:dataSource-ref="dataSource"/>

</beans>

模板Bean 定义不必在 XML 中声明。 允许任何格式(凹槽、注释等)。

7.8.2. 使用自动连线和注释进行配置

缺省情况下,如果未找到 Bean 定义,将自动连接声明实例。这意味着,除非实例提供任何依赖关系注入元数据, 容器将找到对象资源库并尝试自动满足这些依赖项。 但是,开发人员也可以使用 JDK 5 注释为自动连线过程提供其他信息。​​WiringDeclarableSupport​

我们强烈建议阅读 Spring 文档中的专门章节,了解有关支持的注释和支持因素的更多信息。

例如,上面的假设声明可以通过以下方式注入 Spring 配置:​​DBLoader​​​​DataSource​

class DBLoader extends WiringDeclarableSupport implements CacheLoader {

// use annotations to 'mark' the needed dependencies
@javax.inject.Inject
private DataSource dataSource;

public Object load(LoaderHelper helper) { ... }
}
<cache-loader>
<class-name>com.company.app.DBLoader</class-name>
<!-- no need to declare any parameters since the class is auto-wired -->
</cache-loader>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd
">

<!-- enable annotation processing -->
<context:annotation-config/>

</beans>

通过使用JSR-330注释,代码自定位和创建以来得到了简化 的已经外部化,用户代码只关心加载过程。 可能是事务性的、懒惰创建的、在多个对象之间共享的或从 JNDI 检索的。 这些方面可以通过 Spring 容器轻松配置和更改,而无需接触 代码。​​CacheLoader​​​​DataSource​​​​DataSource​​​​DBLoader​

7.9. 支持 Spring 缓存抽象

Spring Data for Apache Geode 提供了 SpringCache Abstraction的实现,将 Apache Geode 定位为 Spring 缓存基础设施中的缓存提供程序

要使用Apache Geode作为支持实现,Spring的缓存抽象中的缓存提供程序”, 只需添加到您的配置中:​​GemfireCacheManager​

<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:cache="http://www.springframework.org/schema/cache"
xmlns:gfe="https://www.springframework.org/schema/geode"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/cache https://www.springframework.org/schema/cache/spring-cache.xsd
https://www.springframework.org/schema/geode https://www.springframework.org/schema/geode/spring-geode.xsd
">

<!-- enable declarative caching -->
<cache:annotation-driven/>

<gfe:cache id="gemfire-cache"/>

<!-- declare GemfireCacheManager; must have a bean ID of 'cacheManager' -->
<bean id="cacheManager" class="org.springframework.data.gemfire.cache.GemfireCacheManager"
p:cache-ref="gemfire-cache">

</beans>

如果默认缓存 Bean 名称,则不需要 bean 定义上的属性 使用(即“gemfireCache”),即没有显式 ID。​​cache-ref​​​​CacheManager​​​​<gfe:cache>​

声明(单例)Bean 实例并启用声明性高速缓存时 (无论是在XML中,还是在JavaConfig中使用Spring'sannotation), Spring 缓存注释(例如)标识将在内存中缓存数据的“缓存” 使用 Apache Geode Regions。​​GemfireCacheManager​​​​<cache:annotation-driven/>​​​​@EnableCaching​​​​@Cacheable​

这些缓存(即区域)必须在使用它们的缓存注释之前存在,否则会发生错误。

例如,假设您有一个带有应用程序组件的客户服务应用程序 执行缓存...​​CustomerService​

@Service
class CustomerService {

@Cacheable(cacheNames="Accounts", key="#customer.id")
Account createAccount(Customer customer) {
...
}

然后,您将需要以下配置。

.XML:

<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:cache="http://www.springframework.org/schema/cache"
xmlns:gfe="https://www.springframework.org/schema/geode"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/cache https://www.springframework.org/schema/cache/spring-cache.xsd
https://www.springframework.org/schema/geode https://www.springframework.org/schema/geode/spring-geode.xsd
">

<!-- enable declarative caching -->
<cache:annotation-driven/>

<bean id="cacheManager" class="org.springframework.data.gemfire.cache.GemfireCacheManager">

<gfe:cache/>

<gfe:partitioned-region id="accountsRegion" name="Accounts" persistent="true" ...>
...
</gfe:partitioned-region>
</beans>

JavaConfig:

@Configuration
@EnableCaching
class ApplicationConfiguration {

@Bean
CacheFactoryBean gemfireCache() {
return new CacheFactoryBean();
}

@Bean
GemfireCacheManager cacheManager() {
GemfireCacheManager cacheManager = GemfireCacheManager();
cacheManager.setCache(gemfireCache());
return cacheManager;
}

@Bean("Accounts")
PartitionedRegionFactoryBean accountsRegion() {
PartitionedRegionFactoryBean accounts = new PartitionedRegionFactoryBean();

accounts.setCache(gemfireCache());
accounts.setClose(false);
accounts.setPersistent(true);

return accounts;
}
}

当然,您可以自由选择您喜欢的任何区域类型(例如复制,分区,本地等)。

有关Spring 缓存抽象的更多详细信息,请参阅文档。

8. 使用 Apache Geode 序列化

为了提高 Apache Geode 内存数据网格的整体性能,Apache Geode 支持专用的 序列化协议,称为 PDX,与标准 Java 序列化相比,它速度更快,结果更紧凑 除了跨各种语言平台(Java、C++ 和 .NET)透明地工作。

有关更多详细信息,请参阅 PDX 序列化​​功能和 PDX 序列化​​​​内部。​

本章讨论 Spring Data for Apache Geode 简化和改进 Apache Geode 的各种方式 Java 中的自定义序列化。

8.1. 连接反序列化实例

序列化对象具有瞬态数据是相当常见的。瞬态数据通常取决于系统 或它在某个时间点居住的环境。例如,特定于环境的 ais 环境。 序列化此类信息是无用的,甚至可能很危险,因为它是某个 VM 或计算机的本地信息。 对于这种情况,Spring Data for Apache Geode 提供了一个特殊的实例化器,用于在反序列化期间为 Apache Geode 创建的每个新实例执行连接。​​DataSource​

通过这样的机制,你可以依靠 Spring 容器来注入和管理某些依赖,让它变得容易 将瞬态数据与持久性数据分开,并以透明的方式拥有丰富的域对象。

Spring 用户可能会发现这种方法类似于 @Configurable)。 作品类似于,试图首先找到一个豆子定义 作为布线模板,否则回退到自动布线。​​WiringInstantiator​​​​WiringDeclarableSupport​

有关接线功能的更多详细信息,请参阅上一节(接线可声明组件)。

要使用 SDG,请将其声明为 bean,如以下示例所示:​​Instantiator​

<bean id="instantiator" class="org.springframework.data.gemfire.serialization.WiringInstantiator">
<!-- DataSerializable type -->
<constructor-arg>org.pkg.SomeDataSerializableClass</constructor-arg>
<!-- type id -->
<constructor-arg>95</constructor-arg>
</bean>

在 Spring 容器启动期间,一旦初始化,默认情况下,它会将自身注册到 Apache Geode 序列化系统,并在创建的所有实例上执行布线 由 Apache Geode 在反序列化期间提供。​​Instantiator​​​​SomeDataSerializableClass​

8.2. 自动生成自定义​​Instantiators​

对于数据密集型应用程序,随着数据流入,可能会在每台计算机上创建大量实例。 Apache Geode 使用反射来创建新类型,但在某些情况下,这可能证明是昂贵的。 与往常一样,最好执行分析以量化是否是这种情况。对于这种情况,Spring Data for Apache Geode 允许自动生成类,该类实例化新类型(使用默认构造函数) 不使用反射。以下示例演示如何创建实例化器:​​Instatiator​

<bean id="instantiatorFactory" class="org.springframework.data.gemfire.serialization.InstantiatorFactoryBean">
<property name="customTypes">
<map>
<entry key="org.pkg.CustomTypeA" value="1025"/>
<entry key="org.pkg.CustomTypeB" value="1026"/>
</map>
</property>
</bean>

前面的定义自动生成两个类(和) 并在用户IDand下将它们注册到Apache Geode。二避免使用 反射并直接通过 Java 代码创建实例。​​Instantiators​​​​CustomTypeA​​​​CustomTypeB​​​​1025​​​​1026​​​​Instantiators​

9. POJO映射

本节涵盖:

  • 实体映射
  • 存储库映射
  • MappingPdxSerializer

9.1. 对象映射基础

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

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

  1. 使用公开的构造函数之一创建实例。
  2. 实例填充以具体化所有公开的属性。

9.1.1. 对象创建

Spring Data 自动尝试检测持久实体的构造函数,以用于具体化该类型的对象。 解析算法的工作原理如下:

  1. 如果有一个静态工厂方法注释,则使用它。@PersistenceCreator
  2. 如果只有一个构造函数,则使用它。
  3. 如果有多个构造函数,并且只有一个被批注,则使用它。@PersistenceCreator
  4. 如果存在无参数构造函数,则使用它。 其他构造函数将被忽略。

值解析假定构造函数/工厂方法参数名称与实体的属性名称匹配,即解析将像要填充属性一样执行,包括映射中的所有自定义(不同的数据存储列或字段名称等)。 这还需要类文件中可用的参数名称信息或构造函数上存在的枚举注释。​​@ConstructorProperties​

值解析可以通过使用特定于商店的SpEL表达式使用Spring Framework的值注释来自定义。 有关更多详细信息,请参阅商店特定映射部分。​​@Value​

对象创建内部

为了避免反射的开销,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 数据将通过反射回退到实体实例化。

9.1.2. 财产人口

创建实体的实例后,Spring Data 将填充该类的所有剩余持久属性。 除非已由实体的构造函数填充(即通过其构造函数参数列表使用),否则将首先填充标识符属性以允许解析循环对象引用。 之后,将在实体实例上设置构造函数尚未填充的所有非瞬态属性。 为此,我们使用以下算法:

  1. 如果属性是不可变的,但公开了 amethod(见下文),我们使用该方法创建一个具有新属性值的新实体实例。with…with…
  2. 如果定义了属性访问(即通过 getter 和 setter 的访问),我们将调用 setter 方法。
  3. 如果属性是可变的,我们直接设置字段。
  4. 如果属性是不可变的,我们将使用持久性操作要使用的构造函数(请参阅对象创建)来创建实例的副本。
  5. 默认情况下,我们直接设置字段值。

属性人口内部

与对象构造中的优化类似,我们还使用 Spring 数据运行时生成的访问器类与实体实例进行交互。

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;
}
}

例 1.生成的属性访问器

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);
}
}
}


PropertyAccessor 保存基础对象的可变实例。这是为了启用其他不可变属性的突变。


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


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


使用属性访问允许直接调用方法,而无需使用。​​MethodHandles​

这为我们提供了大约 25% 的性能提升。 要使域类符合此类优化的条件,它需要遵守一组约束:

  • 类型不得驻留在默认值或包下。java
  • 类型及其构造函数必须是public
  • 内部类的类型必须是。static
  • 使用的 Java 运行时必须允许在原始文件中声明类。Java 9 及更高版本施加了某些限制。ClassLoader

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

让我们看一下以下实体:

例 2.示例实体

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;
}
}


标识符属性是最终的,但在构造函数中设置为。

该类公开用于设置标识符的方法,例如,当实例插入数据存储并生成标识符时。创建新实例时,原始实例保持不变。相同的模式通常应用于存储管理的其他属性,但可能必须更改持久性操作。wither 方法是可选的,因为持久性构造函数(参见 6)实际上是一个复制构造函数,设置属性将转换为创建应用了新标识符值的新实例。​​null​​​​withId(…)​​​​Person​


和属性是普通的不可变属性,可能通过 getter 公开。​​firstname​​​​lastname​


属性是不可变的,但派生自属性。

按照所示的设计,数据库值将胜过默认值,因为 Spring Data 使用唯一声明的构造函数。即使意图是首选计算,重要的是此构造函数也采用 as 参数(可能忽略它),否则属性填充步骤将尝试设置 age 字段并失败,因为它是不可变的并且不存在任何方法。​​age​​​​birthday​​​​age​​​​with…​


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


属性是可变的,并通过直接设置 thefield 或通过调用 setter 方法来填充​​remarks​​​​comment​


该类公开用于创建对象的工厂方法和构造函数。

这里的核心思想是使用工厂方法而不是其他构造函数,以避免通过构造函数消除歧义的需要。相反,属性的默认值在工厂方法中处理。如果您希望 Spring Data 使用工厂方法进行对象实例化,请使用 注释。​​@PersistenceCreator​​​​@PersistenceCreator​

9.1.3. 一般建议

  • 尝试坚持使用不可变对象 - 不可变对象很容易创建,因为具体化对象只需调用其构造函数即可。 此外,这可以避免域对象充斥着允许客户端代码操作对象状态的 setter 方法。 如果需要这些,最好使它们受到包保护,以便只能由有限数量的共存类型调用它们。 仅构造函数具体化比属性填充快 30%。
  • 提供全参数构造函数 — 即使不能或不想将实体建模为不可变值,提供将实体的所有属性(包括可变属性)作为参数的构造函数仍然有价值,因为这允许对象映射跳过属性填充以获得最佳性能。
  • 使用工厂方法而不是重载的构造函数来避免​​@PersistenceCreator​​ — 使用最佳性能所需的全参数构造函数,我们通常希望公开更多特定于应用程序用例的构造函数,这些构造函数省略了自动生成的标识符等内容。 这是一种既定模式,而是使用静态工厂方法来公开 all-args 构造函数的这些变体。
  • 确保遵守允许使用生成的实例化器和属性访问器类的约束
  • 对于要生成的标识符,仍将最终字段与全参数持久性构造函数(首选)或​​with​​...方法
  • 使用 Lombok 避免样板代码 — 由于持久性操作通常需要构造函数获取所有参数,因此它们的声明变成了对字段分配的繁琐重复,而使用 Lombok 可以最好地避免这些参数。@AllArgsConstructor
覆盖属性

Java允许灵活设计域类,其中子类可以定义已在其超类中声明具有相同名称的属性。 请考虑以下示例:

public class SuperType {

private CharSequence field;

public SuperType(CharSequence field) {
this.field = field;
}

public CharSequence getField() {
return this.field;
}

public void setField(CharSequence field) {
this.field = field;
}
}

public class SubType extends SuperType {

private String field;

public SubType(String field) {
super(field);
this.field = field;
}

@Override
public String getField() {
return this.field;
}

public void setField(String field) {
this.field = field;

// optional
super.setField(field);
}
}

这两个类都使用可赋值类型定义。 根据类设计,使用构造函数可能是唯一的默认设置方法。 或者,调用二传手可以设置。 所有这些机制在某种程度上都会产生冲突,因为属性共享相同的名称,但可能表示两个不同的值。 如果类型不可分配,则 Spring Data 将跳过超类型属性。 也就是说,重写属性的类型必须可分配给其超类型属性类型才能注册为重写,否则超类型属性被视为暂时性属性。 我们通常建议使用不同的属性名称。​​field​​​​SubType​​​​SuperType.field​​​​SuperType.field​​​​super.setField(…)​​​​field​​​​SuperType​

Spring 数据模块通常支持保存不同值的被覆盖属性。 从编程模型的角度来看,需要考虑以下几点:

  1. 应保留哪个属性(默认为所有声明的属性)? 您可以通过用这些属性批注来排除属性。@Transient
  2. 如何表示数据存储中的属性? 对不同的值使用相同的字段/列名称通常会导致数据损坏,因此应使用显式字段/列名称至少对其中一个属性进行批注。
  3. 不能使用,因为如果不对 setter 实现进行任何进一步的假设,通常无法设置超级属性。@AccessType(PROPERTY)

9.1.4. Kotlin 支持

Spring Data 调整了 Kotlin 的细节,以允许对象创建和更改。

Kotlin 对象创建

Kotlin 类支持实例化,默认情况下所有类都是不可变的,并且需要显式属性声明来定义可变属性。 请考虑以下类:​​data​​​​Person​

data class Person(val id: String, val name: String)

上面的类编译为具有显式构造函数的典型类。我们可以通过添加另一个构造函数来自定义此类并对其进行注释以指示构造函数首选项:​​@PersistenceCreator​

data class Person(var id: String, val name: String) {

@PersistenceCreator
constructor(id: String) : this(id, "unknown")
}

Kotlin 通过允许在未提供参数时使用默认值来支持参数可选性。 当 Spring Data 检测到参数默认值的构造函数时,如果数据存储不提供值(或只是返回),则这些参数将保留为不存在,以便 Kotlin 可以应用参数默认值。请考虑以下应用参数默认值的类​​null​​​​name​

data class Person(var id: String, val name: String = "unknown")

每次参数不是结果的一部分或其值是时,则默认为。​​name​​​​null​​​​name​​​​unknown​

Kotlin 数据类的属性填充

在 Kotlin 中,默认情况下所有类都是不可变的,并且需要显式属性声明来定义可变属性。 请考虑以下类:​​data​​​​Person​

data class Person(val id: String, val name: String)

此类实际上是不可变的。 它允许在 Kotlin 生成方法时创建新实例,该方法创建新的对象实例,从现有对象复制所有属性值,并将作为参数提供的属性值应用于该方法。​​copy(…)​

Kotlin 覆盖属性

Kotlin 允许声明属性覆盖以更改子类中的属性。

open class SuperType(open var field: Int)

class SubType(override var field: Int = 1) :
SuperType(field) {
}

这种安排呈现两个具有名称的属性。 Kotlin 为每个类中的每个属性生成属性访问器(getter 和 setter)。 实际上,代码如下所示:​​field​

public class SuperType {

private int field;

public SuperType(int field) {
this.field = field;
}

public int getField() {
return this.field;
}

public void setField(int field) {
this.field = field;
}
}

public final class SubType extends SuperType {

private int field;

public SubType(int field) {
super(field);
this.field = field;
}

public int getField() {
return this.field;
}

public void setField(int field) {
this.field = field;
}
}

吉特和二传手仅发病,不发病。 在这种安排中,使用构造函数是唯一要设置的默认方法。 可以添加方法toto setvia,但不属于支持的约定。 属性重写在某种程度上会产生冲突,因为属性共享相同的名称,但可能表示两个不同的值。 我们通常建议使用不同的属性名称。​​SubType​​​​SubType.field​​​​SuperType.field​​​​SuperType.field​​​​SubType​​​​SuperType.field​​​​this.SuperType.field = …​

Spring 数据模块通常支持保存不同值的被覆盖属性。 从编程模型的角度来看,需要考虑以下几点:

  1. 应保留哪个属性(默认为所有声明的属性)? 您可以通过用这些属性批注来排除属性。@Transient
  2. 如何表示数据存储中的属性? 对不同的值使用相同的字段/列名称通常会导致数据损坏,因此应使用显式字段/列名称至少对其中一个属性进行批注。
  3. 使用不能使用,因为无法设置超级属性。​​@AccessType(PROPERTY)​

9.2. 实体映射

Spring Data for Apache Geode 支持映射存储在区域中的实体。映射元数据由下式定义 对应用程序域类使用批注,如以下示例所示:

例 3.将域类映射到 Apache Geode 区域

@Region("People")
public class Person {

@Id Long id;

String firstname;
String lastname;

@PersistenceConstructor
public Person(String firstname, String lastname) {
// …
}


}

注释可用于自定义存储类实例的区域。 注释可用于注释应用作缓存区域键的属性,标识 区域条目。注释有助于消除多个潜在可用的歧义 构造函数,获取参数并显式标记注释为构造函数的构造函数,以用于 构造实体。在没有构造函数或只有一个构造函数的应用程序域类中,可以省略注释。​​@Region​​​​Person​​​​@Id​​​​@PersistenceConstructor​

除了在顶级区域中存储实体外,实体还可以存储在子区域中, 如以下示例所示:

@Region("/Users/Admin")
public class Admin extends User {

}

@Region("/Users/Guest")
public class Guest extends User {

}

确保使用 Apache Geode 区域的完整路径,如 Spring Data for Apache Geode XML 命名空间所定义的那样 通过使用元素的理论属性。​​id​​​​name​​​​<*-region>​

9.2.1. 按区域类型划分的实体映射

除了注释之外,Spring Data for Apache Geode 还可以识别特定于类型的区域映射注释:,,, 和。​​@Region​​​​@ClientRegion​​​​@LocalRegion​​​​@PartitionRegion​​​​@ReplicateRegion​

从功能上讲,这些注释与可持续发展目标中的通用注释完全相同 映射基础设施。但是,这些额外的映射注释在 Apache Geode 的 Spring Data 中很有用。 注释配置模型。与配置注释结合使用时 在 Springannotated 类上,可以在本地缓存中生成区域,无论 应用程序是客户端或对等方。​​@Region​​​​@EnableEntityDefinedRegions​​​​@Configuration​

通过这些注释,您可以更具体地了解应用程序实体类应映射到的区域类型 并且还对区域的数据管理策略产生影响(例如,分区(也称为分片)与复制数据)。

将这些特定于类型的区域映射注释与 SDG 注释配置模型结合使用可节省您的成本 不必在配置中显式定义这些区域。

9.3. 仓库映射

作为使用注释指定存储实体的区域的替代方法 在实体类上,还可以在实体的接口上指定注释。 有关更多详细信息,请参阅Spring Data for Apache Geode Repository。​​@Region​​​​@Region​​​​Repository​

但是,假设您要将记录存储在多个 Apache Geode 区域(例如,和)中。然后,您可以按如下方式定义相应的接口扩展:​​Person​​​​People​​​​Customers​​​​Repository​

@Region("People")
public interface PersonRepository extends GemfireRepository<Person, String> {

}

@Region("Customers")
public interface CustomerRepository extends GemfireRepository<Person, String> {
...
}

然后,单独使用每个存储库,您可以将实体存储在多个 Apache Geode 区域中, 如以下示例所示:

@Service
class CustomerService {

CustomerRepository customerRepo;

PersonRepository personRepo;

Customer update(Customer customer) {
customerRepo.save(customer);
personRepo.save(customer);
return customer;
}

您甚至可以将服务方法包装在 Spring 托管事务中,也可以作为本地缓存事务包装。 或全球交易。​​update​

9.4. 映射Pdx序列化程序

Spring Data for Apache Geode 提供了一个自定义的PdxSerializer实现,称为 Spring Data 映射元数据来自定义实体序列化。​​MappingPdxSerializer​

序列化程序还允许您使用 Spring 数据抽象自定义实体实例化。 默认情况下,序列化程序使用 ,它使用 的持久性构造函数 映射的实体。持久性构造函数要么是默认构造函数,要么是单独声明的构造函数, 或显式批注的构造函数。​​EntityInstantiator​​​​ReflectionEntityInstantiator​​​​@PersistenceConstructor​

为了为构造函数参数提供参数,序列化程序读取具有命名构造函数参数的字段, 通过使用 Spring 的 sannotation 从提供的PdxReader 中显式标识, 如以下示例所示:​​@Value​

例 4.使用实体构造函数参数​​@Value​

public class Person {

public Person(@Value("#root.thing") String firstName, @Value("bean") String lastName) {

}
}

以这种方式注释的实体类具有从 the和 传递的“thing”字段作为参数值传递 对于构造函数参数,。值为名为“bean”的春豆。​​PdxReader​​​​firstname​​​​lastName​

除了自定义实例化逻辑和策略提供之外, 它还提供了远远超出Apache Geode自己的ReflectionBasedAutoSerializer的功能。​​EntityInstantiators​​​​MappingPdxSerializer​

而Apache Geode方便地使用Java Reflect来填充实体 并使用正则表达式来标识应由序列化程序处理(序列化和反序列化)的类型, 它不能像这样执行以下操作:​​ReflectionBasedAutoSerializer​​​​MappingPdxSerializer​

  • 为每个实体字段或属性名称和类型注册自定义对象。PdxSerializer
  • 方便地标识 ID 属性。
  • 自动处理只读属性。
  • 自动处理瞬态属性。
  • 允许以 aand 类型安全的方式进行更可靠的类型筛选(例如,不限于 仅使用正则表达式表示类型)。null

现在,我们将更详细地探讨每个功能。​​MappingPdxSerializer​

9.4.1. 自定义 Pdx 序列化程序注册

这使您能够根据实体的字段注册自定义 或属性名称和类型。​​MappingPdxSerializer​​​​PdxSerializers​

例如,假设您已经定义了一个实体类型,如下所示:​​User​

package example.app.security.auth.model;

public class User {

private String name;

private Password password;

...
}

虽然用户名可能不需要任何特殊逻辑来序列化值,但序列化密码 另一方面,可能需要其他逻辑来处理字段或属性的敏感性。

也许您想在通过网络在客户端和服务器之间发送值时保护密码, 除了 TLS 之外,您只想存储加盐哈希。使用时,您可以注册 自定义处理用户的密码,如下所示:​​MappingPdxSerializer​​​​PdxSerializer​

例 5.注册自定义按 POJO 字段/属性类型​​PdxSerializers​

Map<?, PdxSerializer> customPdxSerializers = new HashMap<>();

customPdxSerializers.put(Password.class, new SaltedHashPasswordPdxSerializer());

mappingPdxSerializer.setCustomPdxSerializers(customPdxSerializers);

使用应用程序域模型类型注册应用程序定义的实例后,将咨询自定义以序列化和反序列化所有对象,而不考虑包含的对象(例如,)。​​SaltedHashPasswordPdxSerializer​​​​Password​​​​MappingPdxSerializer​​​​PdxSerializer​​​​Password​​​​User​

但是,假设您要自定义仅对象上的序列化。 为此,您可以通过指定完全限定名称来注册类型的自定义 字段或属性,如以下示例所示:​​Passwords​​​​User​​​​PdxSerializer​​​​User​​​​Class’s​

例 6.注册自定义 POJO 字段/属性名称​​PdxSerializers​

Map<?, PdxSerializer> customPdxSerializers = new HashMap<>();

customPdxSerializers.put("example.app.security.auth.model.User.password", new SaltedHashPasswordPdxSerializer());

mappingPdxSerializer.setCustomPdxSerializers(customPdxSerializers);

请注意使用完全限定的字段或属性名称(即) 作为自定义注册密钥。​​example.app.security.auth.model.User.password​​​​PdxSerializer​

可以使用逻辑更合理的代码段构造注册密钥,如下所示:我们建议这样做,而不是前面显示的示例。 前面的示例试图尽可能明确地说明注册的语义。​​User.class.getName().concat(".password");​

Apache Geode 的 Spring Data(数据)(四)_apache_02

9.4.2. 映射 ID 属性

与Apache Geode一样,SDG也能够 确定实体的标识符。但是,通过使用 Spring 数据的映射元数据来做到这一点, 特别是通过使用 Spring 数据的注释查找指定为标识符的实体属性​​@Id​​。 或者,任何名为“id”的字段或属性(未明确注释)也被指定为 实体的标识符。​​ReflectionBasedAutoSerializer​​​​MappingPdxSerializer​​​​MappingPdxSerializer​​​​@Id​

例如:

class Customer {

@Id
Long id;

...
}

在这种情况下,当序列化期间调用该方法时,使用​​PdxWriter.markIdentifierField(:String)​​ 将字段标记为 PDX 类型元数据中的标识符字段。​​Customer​​​​id​​​​PdxSerializer.toData(..)​

9.4.3. 映射只读属性

当您的实体定义只读属性时会发生什么情况?

首先,了解什么是“只读”属性非常重要。如果你按照​​JavaBeans​​规范定义POJO(就像Spring所做的那样), 您可以使用只读属性定义 POJO,如下所示:

package example;

class ApplicationDomainType {

private AnotherType readOnly;

public AnotherType getReadOnly() [
this.readOnly;
}

...
}

该属性是只读的,因为它不提供 setter 方法。它只有一个 getter 方法。 在这种情况下,属性(不要与字段混淆) 被视为只读。​​readOnly​​​​readOnly​​​​readOnly​​​​DomainType​

因此,在填充方法中的实例时,将不会尝试为此属性设置值 在反序列化期间,尤其是在 PDX 序列化字节中存在值时。​​MappingPdxSerializer​​​​ApplicationDomainType​​​​PdxSerializer.fromData(:Class<ApplicationDomainType>, :PdxReader)​

这在您可能返回某些实体类型的视图或投影并且您只需要的情况下很有用 设置可写状态。实体的视图或投影可能基于授权或其他 标准。关键是,您可以根据应用程序的用例利用此功能 和要求。如果希望始终写入字段或属性,只需定义一个 setter 方法。

9.4.4. 映射瞬态属性

同样,当您的实体定义属性时会发生什么?​​transient​

您希望在序列化时不会将实体的字段或属性序列化为 PDX 实体。这正是发生的事情,与Apache Geode自己的不同, 它通过 Java 反射序列化可从对象访问的所有内容。​​transient​​​​ReflectionBasedAutoSerializer​

不会序列化任何被限定为瞬态的字段或属性,或者 通过使用 Java 的 own关键字(在类实例字段的情况下)或使用@TransientSpring 数据注释来访问字段或属性。​​MappingPdxSerializer​​​​transient​

例如,您可以定义具有瞬态字段和属性的实体,如下所示:

package example;

class Process {

private transient int id;

private File workingDirectory;

private String name;

private Type type;

@Transient
public String getHostname() {
...
}

...
}

字段和可读属性都不会写入 PDX。​​Process​​​​id​​​​hostname​

9.4.5. 按类类型过滤

与Apache Geode类似,SDG允许您过滤 序列化和反序列化的对象的类型。​​ReflectionBasedAutoSerializer​​​​MappingPdxSerializer​

但是,与Apache Geode不同,Apache Geode使用复杂的正则表达式来表达 序列化程序处理的类型,SDG使用更健壮的java.util.function.Predicate接口 和 API 来表达类型匹配条件。ReflectionBasedAutoSerializerMappingPdxSerializer

如果你喜欢使用正则表达式,你可以实现对Java的正则表达式支持​。​​Predicate​

Java界面的优点是你可以使用方便的方法来组合 和适当的 API 方法,包括:and(:P redicate),or(:P redicate), 和否定()。​​Predicate​​​​Predicates​

以下示例显示了 API 的实际操作:​​Predicate​

Predicate<Class<?>> customerTypes =
type -> Customer.class.getPackage().getName().startsWith(type.getName()); // Include all types in the same package as `Customer`

Predicate includedTypes = customerTypes
.or(type -> User.class.isAssignble(type)); // Additionally, include User sub-types (e.g. Admin, Guest, etc)

mappingPdxSerializer.setIncludeTypeFilters(includedTypes);

mappingPdxSerializer.setExcludeTypeFilters(
type -> !Reference.class.getPackage(type.getPackage()); // Exclude Reference types

任何传递给您的对象都保证不会。​​Class​​​​Predicate​​​​null​

SDG 包括对包含和排除类类型筛选器的支持。​​MappingPdxSerializer​

排除类型筛选

默认情况下,SDG 的寄存器预定义过滤或排除类型 从以下软件包:​​MappingPdxSerializer​​​​Predicates​

  • ​java.*​
  • ​com.gemstone.gemfire.*​
  • ​org.apache.geode.*​
  • ​org.springframework.*​

此外,调用方法时过滤对象和调用方法时的类类型。​​MappingPdxSerializer​​​​null​​​​PdxSerializer.toData(:Object, :PdxWriter)​​​​null​​​​PdxSerializer.fromData(:Class<?>, :PdxReader)​

为其他类类型或整个类型包添加排除项非常容易,只需定义 a 并将其添加到前面所示的 the。​​Predicate​​​​MappingPdxSerializer​

该方法是累加的,这意味着它组成 具有上述现有预定义类型筛选器的应用程序定义类型筛选器 使用方法。​​MappingPdxSerializer.setExcludeTypeFilters(:Predicate<Class<?>>)​​​​Predicates​​​​Predicate.and(:Predicate<Class<?>>)​

但是,如果要包含隐式排除的类类型(例如,),该怎么办 排除类型筛选器?请参阅包括类型筛选。​​java.security Principal​

包括类型筛选

如果要显式包含类类型,或重写隐式排除类类型的类类型筛选器 您的应用程序需要(例如,默认情况下排除,包排除类型过滤器打开),然后只需定义适当的并将其添加到 序列化程序使用方法,如下所示:​​java.security.Principal​​​​java.*​​​​MappingPdxSerializer​​​​Predicate​​​​MappingPdxSerializer.setIncludeTypeFilters(:Predicate<Class<?>>)​

Predicate<Class<?>> principalTypeFilter =
type -> java.security.Principal.class.isAssignableFrom(type);

mappingPdxSerializer.setIncludeTypeFilters(principalTypeFilters);

再次,该方法, 喜欢,是加法的,因此组成任何通过的类型过滤器 用。这意味着您可以根据需要多次调用。​​MappingPdxSerializer.setIncludeTypeFilters(:Predicate<Class<?>>)​​​​setExcludeTypeFilters(:Predicate<Class<?>>)​​​​Predicate.or(:Predicate<Class<?>>)​​​​setIncludeTypeFilters(:Predicate<Class<?>>)​

当存在包含类型筛选器时,则决定是否取消/序列化 类类型的实例,当类类型未被隐式排除或类类型时 显式包含,以返回 true 者为准。然后,将序列化类类型的实例 或适当反序列化。​​MappingPdxSerializer​

例如,当类型筛选器 ofis 显式注册时,如前所示, 它取消了包类型的隐式排除类型筛选器。​​Predicate<Class<Principal>>​​​​java.*​

10. Apache Geode 存储库的 Spring 数据

Spring Data for Apache Geode 支持使用 Spring 数据存储库抽象轻松地将实体持久化到 Apache Geode 以及执行查询。存储库编程模型的一般介绍 此处提供。

10.1. 弹簧 XML 配置

要引导 Spring 数据存储库,请使用 Spring Data for Apache Geode Data 命名空间中的元素, 如以下示例所示:​​<repositories/>​

例 7.Bootstrap Spring Data for Apache Geode Repository in XML

<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:gfe-data="https://www.springframework.org/schema/data/geode"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
https://www.springframework.org/schema/data/geode https://www.springframework.org/schema/data/geode/spring-data-geode.xsd
">

<gfe-data:repositories base-package="com.example.acme.repository"/>

</beans>

前面的配置片段在配置的基本包下查找接口并创建存储库实例 对于由SimpleGemFireRepository 支持的接口。

引导过程将失败,除非您已正确映射应用程序域类 到已配置的区域。

10.2. 基于 Java 的 Spring 配置

或者,许多开发人员更喜欢使用Spring的基于Java的容器配置。

使用这种方法,您可以使用SDG注释引导Spring数据存储库,如以下示例所示:​​@EnableGemfireRepositories​

例 8.Bootstrap Spring Data for Apache Geode Repository with​​@EnableGemfireRepositories​

@SpringBootApplication
@EnableGemfireRepositories(basePackages = "com.example.acme.repository")
class SpringDataApplication {
...
}

您可能更喜欢使用 type-safeattribute 而不是使用属性。 允许您通过以下方式指定包含所有应用程序存储库类的包 仅指定一种应用程序存储库接口类型。考虑创建一个特殊的无操作标记类 或每个包中的接口,除了标识应用程序存储库的位置外,没有任何用途 由此属性引用。​​basePackages​​​​basePackageClasses​​​​basePackageClasses​

除了属性,如春天的@ComponentScan注释, theannotation 根据 Spring 的ComponentScan.Filter类型提供包含和排除过滤器。 您可以使用属性按不同方面进行筛选,例如应用程序是否 存储库类型 使用特定批注进行批注或扩展特定类类型等。有关更多详细信息,请参阅FilterTypeJavadoc。​​basePackages and basePackageClasses​​​​@EnableGemfireRepositories​​​​filterType​

注释还允许您指定命名 OQL 查询的位置,这些查询位于 一个 Javafile,通过使用属性。属性名称必须与名称匹配 存储库查询方法,并且属性值是存储库查询方法时要执行的 OQL 查询 被称为。​​@EnableGemfireRepositories​​​​Properties​​​​namedQueriesLocation​

属性可以设置为备用值(默认为),如果 应用程序需要一个或多个自定义存储库实现。 此功能通常用于扩展 Spring 数据存储库基础架构,以实现 数据存储(例如 SDG)。​​repositoryImplementationPostfix​​​​Impl​

需要使用 Apache Geode 实现自定义存储库的一个例子是执行连接时。 SDG 存储库不支持联接。对于 Apache GeodeRegion,联接必须 在 colatingRegions 上执行,因为 Apache Geode 不支持“分布式”联接。 此外,Equi-join OQL 查询必须在 Apache Geode 函数中执行。 有关 Apache GeodeEqui-Join Query 的更多详细信息,请参阅此处。​​PARTITION​​​​PARTITION​

可持续发展目标存储库基础设施扩展的许多其他方面也可以定制。有关所有配置设置的更多详细信息,请参阅@EnableGemfireRepositoriesJavadoc。

10.3. 执行 OQL 查询

Spring Data for Apache Geode Repository支持定义查询方法,以轻松执行Apache Geode OQL查询 针对托管实体映射到的区域,如以下示例所示:

例 9.示例存储库

@Region("People")
public class Person { … }
public interface PersonRepository extends CrudRepository<Person, Long> {

Person findByEmailAddress(String emailAddress);

Collection<Person> findByFirstname(String firstname);

@Query("SELECT * FROM /People p WHERE p.firstname = $1")
Collection<Person> findByFirstnameAnnotated(String firstname);

@Query("SELECT * FROM /People p WHERE p.firstname IN SET $1")
Collection<Person> findByFirstnamesAnnotated(Collection<String> firstnames);
}

前面示例中列出的第一个查询方法会导致派生以下 OQL 查询:第二种查询方法的工作方式相同,除了 它返回找到的所有实体,而第一个查询方法期望找到单个结果。​​SELECT x FROM /People x WHERE x.emailAddress = $1​

如果支持的关键字不足以声明和表达 OQL 查询,或者方法名称变得太 详细,然后您可以使用第三和第四种方法所示对查询方法进行注释。​​@Query​

下表提供了可在查询方法中使用的受支持关键字的简要示例:

Table 4. Supported keywords for query methods

关键词

样本

逻辑结果

​GreaterThan​

​findByAgeGreaterThan(int age)​

​x.age > $1​

​GreaterThanEqual​

​findByAgeGreaterThanEqual(int age)​

​x.age >= $1​

​LessThan​

​findByAgeLessThan(int age)​

​x.age < $1​

​LessThanEqual​

​findByAgeLessThanEqual(int age)​

​x.age ⇐ $1​

​IsNotNull​​​, ​​NotNull​

​findByFirstnameNotNull()​

​x.firstname =! NULL​

​IsNull​​​, ​​Null​

​findByFirstnameNull()​

​x.firstname = NULL​

​In​

​findByFirstnameIn(Collection<String> x)​

​x.firstname IN SET $1​

​NotIn​

​findByFirstnameNotIn(Collection<String> x)​

​x.firstname NOT IN SET $1​

​IgnoreCase​

​findByFirstnameIgnoreCase(String firstName)​

​x.firstname.equalsIgnoreCase($1)​

(无关键字)

​findByFirstname(String name)​

​x.firstname = $1​

​Like​

​findByFirstnameLike(String name)​

​x.firstname LIKE $1​

​Not​

​findByFirstnameNot(String name)​

​x.firstname != $1​

​IsTrue​​​, ​​True​

​findByActiveIsTrue()​

​x.active = true​

​IsFalse​​​, ​​False​

​findByActiveIsFalse()​

​x.active = false​

10.4. 使用注释的 OQL 查询扩展

许多查询语言,如Apache Geode的OQL(对象查询语言),都有不直接的扩展。 由Spring Data Commons的存储库基础架构支持。

Spring Data Commons的存储库基础架构目标之一是充当要维护的最低公分母 支持和可移植到可用于应用程序开发的最广泛的数据存储 今天。从技术上讲,这意味着开发人员可以访问Spring Data Commons支持的多个不同数据存储。 在他们的应用程序中,通过重用他们现有的特定于应用程序的存储库接口 — 一个方便的 和强大的抽象。

为了支持 Apache Geode 的 OQL Query 语言扩展并保持跨不同数据存储的可移植性, Spring Data for Apache Geode 通过使用 Java 注释增加了对 OQL Query 扩展的支持。这些注释被其他注释忽略 没有类似功能的 Spring 数据存储库实现(例如 Spring Data JPA 或 Spring Data Redis) 查询语言功能。

例如,许多数据存储很可能没有实现Apache Geode的OQL关键字。实现为注释(即),而不是查询方法签名的一部分(特别是方法“name”) 在计算查询方法名称以构造另一个数据存储时不会干扰分析基础结构 语言适当的查询。​​IMPORT​​​​IMPORT​​​​@Import​

目前,Spring Data for Apache Geode 支持的 Apache Geode OQL Query 语言扩展集包括:

Table 5. Supported Apache Geode OQL extensions for Repository query methods

关键词

注解

描述

参数

提示

​@Hint​

OQL 查询索引提示

​String[]​​(例如 @Hint({ “IdIdx”, “TxDateIdx” }))

进口

​@Import​

限定特定于应用程序的类型。

​String​​(例如@Import(“org.example.app.domain.Type”))

限制

​@Limit​

限制返回的查询结果集。

​Integer​​(例如 @Limit(10);默认值为 Integer.MAX_VALUE)

跟踪

​@Trace​

启用特定于 OQL 查询的调试。

例如,假设您有一个应用程序域类和相应的 Apache Geode 区域 以及 aand 查询方法按姓氏查找,如下所示:​​Customers​​​​CustomerRepository​​​​Customers​

例 10.示例客户存储库

package ...;

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

@Region("Customers")
public class Customer ... {

@Id
private Long id;

...
}
package ...;

import org.springframework.data.gemfire.repository.GemfireRepository;
...

public interface CustomerRepository extends GemfireRepository<Customer, Long> {

@Trace
@Limit(10)
@Hint("LastNameIdx")
@Import("org.example.app.domain.Customer")
List<Customer> findByLastName(String lastName);

...
}

前面的示例生成以下 OQL 查询:

​<TRACE> <HINT 'LastNameIdx'> IMPORT org.example.app.domain.Customer; SELECT * FROM /Customers x WHERE x.lastName = $1 LIMIT 10​

Apache Geode的存储库扩展的Spring Data在OQL注释扩展时注意不要创建冲突的声明 与注释结合使用。​​@Query​

再举一个例子,假设你有一个在 如下:​​@Query​​​​CustomerRepository​

例 11.客户存储库

public interface CustomerRepository extends GemfireRepository<Customer, Long> {

@Trace
@Limit(10)
@Hint("CustomerIdx")
@Import("org.example.app.domain.Customer")
@Query("<TRACE> <HINT 'ReputationIdx'> SELECT DISTINCT * FROM /Customers c WHERE c.reputation > $1 ORDER BY c.reputation DESC LIMIT 5")
List<Customer> findDistinctCustomersByReputationGreaterThanOrderByReputationDesc(Integer reputation);

}

上述查询方法生成以下 OQL 查询:

​IMPORT org.example.app.domain.Customer; <TRACE> <HINT 'ReputationIdx'> SELECT DISTINCT * FROM /Customers x WHERE x.reputation > $1 ORDER BY c.reputation DESC LIMIT 5​

注释不会覆盖原始查询中显式定义的注释。 此外,注释不会覆盖原始查询中显式定义的注释。 最后,注释是多余的,没有额外的效果。​​@Limit(10)​​​​LIMIT​​​​@Hint("CustomerIdx")​​​​HINT​​​​@Trace​


Theindex可能不是最明智的指数,考虑到可能拥有的客户数量 他们的声誉具有相同的价值,这会降低指数的有效性。请选择索引和其他 明智地进行优化,因为不正确或选择不当的索引可能会对您的性能产生相反的影响,因为 维护索引的开销。Thewas仅用于示例的目的。​​ReputationIdx​​​​ReputationIdx​


10.5. 查询后处理

由于使用了 Spring 数据存储库抽象,用于定义特定于数据存储的查询方法约定 查询(例如 OQL)既简单又方便。但是,有时仍希望检查甚至可能检查 修改从存储库查询方法生成的查询。

从 2.0.x 开始,Spring Data for Apache Geode 包含功能接口。 接口松散定义如下:​​o.s.d.gemfire.repository.query.QueryPostProcessor​

例 12.查询后处理器

package org.springframework.data.gemfire.repository.query;

import org.springframework.core.Ordered;
import org.springframework.data.repository.Repository;
import org.springframework.data.repository.query.QueryMethod;
import ...;

@FunctionalInterface
interface QueryPostProcessor<T extends Repository, QUERY> extends Ordered {

QUERY postProcess(QueryMethod queryMethod, QUERY query, Object... arguments);

}

还提供了其他默认方法,可让您编写类似于java.util.function.Function.andThen(:Function)和java.util.function.Function.compose(:Function)的工作方式的实例。QueryPostProcessor

此外,该接口实现了org.springframework.core.Order接口, 当多个在 Spring 容器中声明和注册并用于 为一组生成的查询方法查询创建处理管道。QueryPostProcessorQueryPostProcessors

最后,接受类型参数对应的类型参数,并且, 分别。类型扩展了Spring Data Commons标记接口,org.springframework.data.repository.Repository。 我们将在本节后面进一步讨论这一点。对于Apache Geode的情况,Spring Data中的Alltype参数参数是类型。​​QueryPostProcessor​​​​T​​​​QUERY​​​​T​​​​QUERY​​​​java.lang.String​

将查询定义为类型很有用,因为此接口可以移植到 Spring Data Commons,因此必须处理不同数据存储(如JPA,MongoDB, 或雷迪斯)。​​QUERY​​​​QueryPostProcessor​

可以实现此接口,以接收调用方法时从应用程序接口方法生成的查询的回调。​​Repository​

例如,您可能希望记录来自所有应用程序存储库接口定义的所有查询。你可以这样做 通过使用以下实现:​​QueryPostProcessor​

例 13.LoggingQueryPostProcessor

package example;

import ...;

class LoggingQueryPostProcessor implements QueryPostProcessor<Repository, String> {

private Logger logger = Logger.getLogger("someLoggerName");

@Override
public String postProcess(QueryMethod queryMethod, String query, Object... arguments) {

String message = String.format("Executing query [%s] with arguments [%s]", query, Arrays.toString(arguments));

this.logger.info(message);
}
}

Thewas键入到Spring Datamarker接口,因此,记录所有应用程序存储库接口查询方法生成的查询。​​LoggingQueryPostProcessor​​​​org.springframework.data.repository.Repository​

您可以将此日志记录的范围限制为仅来自某些类型的应用程序存储库接口的查询, 例如,例如,a,如以下示例所示:​​CustomerRepository​

例 14.客户存储库

interface CustomerRepository extends CrudRepository<Customer, Long> {

Customer findByAccountNumber(String accountNumber);

List<Customer> findByLastNameLike(String lastName);

}

然后,您可以专门键入,如下所示:​​LoggingQueryPostProcessor​​​​CustomerRepository​

例 15。CustomerLoggingQueryPostProcessor

class LoggingQueryPostProcessor implements QueryPostProcessor<CustomerRepository, String> { .. }

因此,仅记录在接口中定义的查询,例如。​​CustomerRepository​​​​findByAccountNumber​

您可能希望为 存储库查询方法定义的特定查询创建 a。例如 假设您要限制从查询方法生成的 OQL 查询 仅返回五个结果以及按升序排序的 theby。为此, 您可以定义自定义,如以下示例所示:​​QueryPostProcessor​​​​CustomerRepository.findByLastNameLike(:String)​​​​Customers​​​​firstName​​​​QueryPostProcessor​

例 16。OrderedLimitedCustomerByLastNameQueryPostProcessor

class OrderedLimitedCustomerByLastNameQueryPostProcessor implements QueryPostProcessor<CustomerRepository, String> {

private final int limit;

public OrderedLimitedCustomerByLastNameQueryPostProcessor(int limit) {
this.limit = limit;
}

@Override
public String postProcess(QueryMethod queryMethod, String query, Object... arguments) {

return "findByLastNameLike".equals(queryMethod.getName())
? query.trim()
.replace("SELECT", "SELECT DISTINCT")
.concat(" ORDER BY firstName ASC")
.concat(String.format(" LIMIT %d", this.limit))
: query;
}
}

虽然前面的示例有效,但您可以使用 Spring 数据存储库约定来实现相同的效果 由Spring Data for Apache Geode提供。例如,可以按如下方式定义相同的查询:

例 17.使用约定的客户存储库

interface CustomerRepository extends CrudRepository<Customer, Long> {

@Limit(5)
List<Customer> findDistinctByLastNameLikeOrderByFirstNameDesc(String lastName);

}

但是,如果您无法控制应用程序接口定义, 那么(即)很方便。​​CustomerRepository​​​​QueryPostProcessor​​​​OrderedLimitedCustomerByLastNameQueryPostProcessor​

如果你想确保总是出现在另一个应用程序定义之后,可能已经在 Spring 中声明和注册了 bean,你可以设置 通过重写方法的属性,如以下示例所示:​​LoggingQueryPostProcessor​​​​QueryPostProcessors​​​​ApplicationContext​​​​order​​​​o.s.core.Ordered.getOrder()​

例 18。定义属性​​order​

class LoggingQueryPostProcessor implements QueryPostProcessor<Repository, String> {

@Override
int getOrder() {
return 1;
}
}

class CustomerQueryPostProcessor implements QueryPostProcessor<CustomerRepository, String> {

@Override
int getOrder() {
return 0;
}
}

这可确保在记录查询之前始终看到其他人应用的后处理的效果。​​QueryPostProcessors​​​​LoggingQueryPostProcessor​

您可以在您喜欢的 Springas 中定义任意数量,并以任何顺序应用它们, 到所有或特定的应用程序存储库接口,并使用提供的参数尽可能精细 到方法回调。​​QueryPostProcessors​​​​ApplicationContext​​​​postProcess(..)​

11. 函数执行的注释支持

Spring Data for Apache Geode 包括注释支持,以简化使用 Apache Geode函数执行。

在后台,Apache Geode API提供了一些类来实现和注册部署在Apache Geode上的Apache Geode函数。 服务器,然后可以由其他对等成员应用程序调用或从缓存客户端远程调用。

函数可以并行执行,分布在集群中的多个Apache Geode服务器之间,聚合 结果使用 map-reduce 模式并发送回调用方。函数也可以针对在单个上运行 服务器或区域。Apache Geode API 支持使用各种预定义的函数远程执行目标函数 范围:在区域、成员(组中)、服务器上等。远程函数的实现和执行, 与任何 RPC 协议一样,需要一些样板代码。

Spring Data for Apache Geode忠于Spring的核心价值主张,旨在隐藏远程函数执行的机制,让你 专注于核心 POJO 编程和业务逻辑。为此,Spring Data for Apache Geode 引入了声明式注释 将POJO类的公共方法注册为Apache Geode函数以及调用已注册的功能 使用带批注的接口的功能(包括远程)。

11.1. 实施与执行

有两个单独的问题需要解决:实施和执行。

第一个是函数实现(服务器端),它必须与FunctionContext交互才能访问调用参数,ResultsSender才能发送结果, 和其他执行上下文信息。函数实现通常访问缓存和区域 并以唯一 ID 在函数服务中注册。

调用函数的缓存客户端应用程序不依赖于实现。要调用函数, 应用程序实例化一个执行,提供函数 ID、调用参数和函数目标,该目标定义其范围: 区域、服务器、服务器、成员或成员。如果函数生成结果,调用程序将使用ResultCollector聚合并获取执行结果。在某些情况下,自定义实现 是必需的,可以注册。​​ResultCollector​​​​Execution​

“客户端”和“服务器”在这里用于函数执行的上下文中,这可能具有不同的含义 比 Apache Geode 的客户端-服务器拓扑中的客户端和服务器。虽然对于使用 a实例在集群中的一个或多个Apache Geode服务器上调用函数,它也是 可以在对等 (P2P) 配置中执行功能,其中应用程序是集群的成员 托管对等实例。请记住,对等成员缓存应用程序受所有约束 成为集群的对等成员。​​ClientCache​​​​Cache​

11.2. 实现函数

使用 Apache Geode API,提供了一个运行时调用上下文,其中包括客户端的 调用参数和实现以将结果发送回客户端。此外,如果函数 在一个区域上执行,这实际上是一个实例,它提供 其他信息,例如调用函数的目标区域、任何筛选器(一组特定键) 与 相关联,依此类推。如果区域是区域,则函数应使用 提取本地数据集。​​FunctionContext​​​​ResultSender​​​​FunctionContext​​​​RegionFunctionContext​​​​Execution​​​​PARTITION​​​​PartitionRegionHelper​

通过使用 Spring,您可以编写一个简单的 POJO,并使用 Spring 容器绑定一个或多个 POJO。 函数的公共方法。打算用作函数的 POJO 方法的签名通常必须符合 到客户端的执行参数。但是,在区域执行的情况下,也可以提供区域数据 (如果区域是区域,则假定数据保存在本地分区中)。​​PARTITION​

此外,该函数可能需要应用的筛选器(如果有)。这表明客户端和服务器 共享调用参数的协定,但方法签名可能包含用于传递值的其他参数 由提供。一种可能性是客户端和服务器共享一个公共接口,但这 不是严格要求的。唯一的约束是方法签名包含相同的调用参数序列 解析附加参数后调用函数。​​FunctionContext​

例如,假设客户端提供 aand anas 调用参数。这些是提供的 在 As 数组中,如以下示例所示:​​String​​​​int​​​​FunctionContext​

​Object[] args = new Object[] { "test", 123 };​

Spring 容器应该能够绑定到类似于以下内容的任何方法签名(忽略返回类型 目前):

public Object method1(String s1, int i2) { ... }
public Object method2(Map<?, ?> data, String s1, int i2) { ... }
public Object method3(String s1, Map<?, ?> data, int i2) { ... }
public Object method4(String s1, Map<?, ?> data, Set<?> filter, int i2) { ... }
public void method4(String s1, Set<?> filter, int i2, Region<?,?> data) { ... }
public void method5(String s1, ResultSender rs, int i2) { ... }
public void method6(FunctionContest context) { ... }

一般规则是,一旦解析了任何其他参数(即区域数据和筛选器), 其余参数的顺序和类型必须与预期的函数方法参数完全对应。 该方法的返回类型必须为 void 或可以序列化的类型(如 a,, 或)。后者也是调用参数的要求。​​java.io.Serializable​​​​DataSerializable​​​​PdxSerializable​

区域数据通常应定义为 a,以便于单元测试,但也可以是区域类型, 如有必要。如前面的示例所示,传递自身也是有效的 或者如果您需要控制如何将结果返回给客户端。​​Map​​​​FunctionContext​​​​ResultSender​

11.2.1. 函数实现的注释

以下示例显示了如何使用 SDG 的函数注释来公开 POJO 方法 作为 Apache Geode 函数:

@Component
public class ApplicationFunctions {

@GemfireFunction
public String function1(String value, @RegionData Map<?, ?> data, int i2) { ... }

@GemfireFunction(id = "myFunction", batchSize=100, HA=true, optimizedForWrite=true)
public List<String> function2(String value, @RegionData Map<?, ?> data, int i2, @Filter Set<?> keys) { ... }

@GemfireFunction(hasResult=true)
public void functionWithContext(FunctionContext functionContext) { ... }

}

请注意,类本身必须注册为 Spring bean,并且每个 Apache Geode 函数都带有注释。在前面的示例中,使用了 Spring'sannotation,但您可以注册 bean 通过使用 Spring 支持的任何方法(例如 XML 配置或使用 Java 配置类,使用 弹簧启动)。这允许 Spring 容器创建此类的实例并将其包装在PojoFunctionWrapper 中。 Spring 为每个注释的方法创建一个包装器实例。每个包装器实例共享 同一目标对象实例以调用相应的方法。​​@GemfireFunction​​​​@Component​​​​@GemfireFunction​

POJO 函数类是 Spring Bean 的事实可能提供其他好处。由于它共享 使用Apache Geode组件,例如缓存和区域,这些组件可以注入到中 类(如有必要)。​​ApplicationContext​

Spring 创建包装类并将函数注册到 Apache Geode。函数标识 用于注册每个函数必须是唯一的。通过使用约定,它默认为简单(非限定)方法名称。 可以使用注释的属性显式定义名称。​​FunctionService​​​​id​​​​@GemfireFunction​

注释还提供了其他配置属性:并且, 对应于 Apache Geode函数接口定义的属性。​​@GemfireFunction​​​​HA​​​​optimizedForWrite​

如果 POJO 函数方法的返回类型为 ,则属性将自动设置为 。 否则,如果该方法返回值,则属性设置为 。甚至方法返回 类型,可以设置注释的属性以覆盖此约定, 如前面所示的方法所示。据推测,目的是您将使用 直接将结果发送给调用方。​​void​​​​hasResult​​​​false​​​​hasResult​​​​true​​​​void​​​​GemfireFunction​​​​hasResult​​​​true​​​​functionWithContext​​​​ResultSender​

最后,注释支持属性,它指定权限 需要执行函数。默认情况下,所有函数都需要权限。属性 接受字符串数组,允许您根据应用程序和/或函数 UC 的要求修改权限。 每个资源权限应采用以下格式:​​GemfireFunction​​​​requiredPermissions​​​​DATA:WRITE​​​​<RESOURCE>:<OPERATION>:[Target]:[Key]​

​RESOURCE​​可以是 {data-store-javadoc]中的 1 个/org/apache/geode/security/ResourcePermission.Resource.html[] 枚举值。可以是 {data-store-javadoc}/org/apache/geode/security/ResourcePermission.Operation.html[] 中的 1 个 枚举值。可选,可以是区域的名称或 1 个区域的名称 {data-store-javadoc}/org/apache/geode/security/ResourcePermission.Target.html[] 枚举值。最后,(可选)是区域中的有效键(如果指定)。​​ResourcePermission.Resource​​​​OPERATION​​​​ResourcePermission.Operation​​​​Target​​​​ResourcePermission.Target​​​​Key​​​​Target​

实现 Apache Geode 的接口,绑定方法参数并调用 其方法中的目标方法。它还将方法的返回值发送回调用方 通过使用。​​PojoFunctionWrapper​​​​Function​​​​execute()​​​​ResultSender​

11.2.2. 批处理结果

如果返回类型是数组或,则必须考虑如何返回结果。 默认情况下,返回整个数组或返回一次。如果元素的数量 在相当大的阵列 ORIS 中,它可能会导致性能损失。要将有效载荷分成更小的, 更易于管理的块,您可以设置属性,如前面所示。​​Collection​​​​PojoFunctionWrapper​​​​Collection​​​​Collection​​​​batchSize​​​​function2​

如果你需要更多的控制,特别是如果方法本身会使用太多内存 若要创建,可以通过 TheR 传入 Access,并直接在方法中使用它来将结果发送回调用方。​​ResultSender​​​​Collection​​​​ResultSender​​​​FunctionContext​

11.2.3. 启用注释处理

根据 Spring 标准,您必须显式激活注释处理forannotations。下面的示例使用 XML 激活批注处理:​​@GemfireFunction​

<gfe:annotation-driven/>

以下示例通过批注 Java 配置类来激活注释处理:

@Configuration
@EnableGemfireFunctions
class ApplicationConfiguration { ... }

11.3. 执行函数

调用远程函数的进程需要提供函数的 ID、调用参数、执行目标 (,,,,或)和(可选)过滤器集。通过使用 Spring Data for Apache Geode, 您需要做的就是定义一个由注释支持的接口。Spring 为接口创建一个动态代理, 它使用 thes 创建一个、调用和(如有必要)强制 定义返回类型的结果。这种技术类似于 Spring Data for Apache Geode 的 Repository 扩展的工作方式。 因此,应该熟悉一些配置和概念。​​onRegion​​​​onServers​​​​onServer​​​​onMember​​​​onMembers​​​​FunctionService​​​​Execution​​​​Execution​

通常,单个接口定义映射到多个函数执行,每个方法对应一个 在接口中定义。

11.3.1. 函数执行的注释

为了支持客户端函数执行,提供了以下 SDG 函数注释:,,,, 和。这些注解对应于Apache Geode的FunctionService类提供的实现。​​@OnRegion​​​​@OnServer​​​​@OnServers​​​​@OnMember​​​​@OnMembers​​​​Execution​

每个批注都公开相应的属性。这些注释还提供可选属性 其值是实现ResultCollector接口的 Spring Bean 的名称 用于执行。​​resultCollector​

下面的清单显示了几个示例:

@OnRegion(region="SomeRegion", resultCollector="myCollector")
public interface FunctionExecution {

@FunctionId("function1")
String doIt(String s1, int i2);

String getString(Object arg1, @Filter Set<Object> keys);

}

默认情况下,函数 ID 是简单(非限定)方法名称。可以使用注释 将此调用绑定到其他函数 ID。​​@FunctionId​

11.3.2. 启用注释处理

客户端使用 Spring 的类路径组件扫描功能来发现带注释的接口。要启用 在 XML 中执行函数注释处理时,在 XML 配置中插入以下元素:

<gfe-data:function-executions base-package="org.example.myapp.gemfire.functions"/>

该元素在 XML 命名空间中提供。属性为必填项 以避免扫描整个类路径。可以按照 Spring参考文档中的说明提供其他过滤器。​​function-executions​​​​gfe-data​​​​base-package​

或者,您可以按如下方式批注 Java 配置类:

@EnableGemfireFunctionExecutions(basePackages = "org.example.myapp.gemfire.functions")

11.4. 程序化函数执行

使用上一节中定义的函数执行带注释的接口,只需自动连接接口即可 放入将调用函数的应用程序 Bean 中:

@Component
public class MyApplication {

@Autowired
FunctionExecution functionExecution;

public void doSomething() {
functionExecution.doIt("hello", 123);
}
}

或者,您可以直接使用函数执行模板。在以下示例中, 创建函数:​​GemfireOnRegionFunctionTemplate​​​​onRegion​​​​Execution​

例 19。使用​​GemfireOnRegionFunctionTemplate​

Set<?, ?> myFilter = getFilter();
Region<?, ?> myRegion = getRegion();
GemfireOnRegionOperations template = new GemfireOnRegionFunctionTemplate(myRegion);
String result = template.executeAndExtract("someFunction", myFilter, "hello", "world", 1234);

在内部,Functionalways 返回 a.假定包含结果的单例,并尝试将该值强制转换为请求的类型。还有一个方法 那返回了 theas 是。第一个参数是函数 ID。筛选器参数是可选的。其余的 参数是一个变量参数。​​Executions​​​​List​​​​executeAndExtract​​​​List​​​​execute​​​​List​​​​List​

11.5. 使用 PDX 执行函数

当将 Spring Data 用于 Apache Geode 的函数注释支持与 Apache Geode 的PDX 序列化结合使用时, 有一些后勤事项需要牢记。

如本节前面所述,作为示例,您通常应该定义 Apache Geode 函数 通过使用带有 Spring Data 注释的 POJO 类进行 Apache Geode函数注释, 如下:

public class OrderFunctions {

@GemfireFunction(...)
Order process(@RegionData data, Order order, OrderSource orderSourceEnum, Integer count) { ... }

}

类型参数是任意的,类的分离也是任意的 和theenum,这可能是合乎逻辑的结合。但是,参数是这样设置的 演示 PDX 上下文中函数执行的问题。​​Integer​​​​count​​​​Order​​​​OrderSource​

您的类 andenum 可以定义如下:​​Order​​​​OrderSource​

public class Order ... {

private Long orderNumber;
private LocalDateTime orderDateTime;
private Customer customer;
private List<Item> items

...
}


public enum OrderSource {
ONLINE,
PHONE,
POINT_OF_SALE
...
}

当然,你可以定义一个函数接口来调用“进程”Apache Geode 服务器函数, 如下:​​Execution​

@OnServer
public interface OrderProcessingFunctions {
Order process(Order order, OrderSource orderSourceEnum, Integer count);
}

显然,这个函数是用一个实例从客户端调用的 (即)。这意味着函数参数也必须是可序列化的。事实也是如此 在集群中的对等方之间调用对等成员函数(例如)时。任何形式的 都要求对客户端和服务器(或对等方)之间传输的数据进行序列化。​​process(..)​​​​Order​​​​ClientCache​​​​<gfe:client-cache/>​​​​@OnMember(s)​​​​distribution​

现在,如果您已将Apache Geode配置为使用PDX进行序列化(例如,而不是Java序列化) 您还可以在配置Apache Geode服务器时设置属性, 如下:​​pdx-read-serialized​​​​true​

<gfe:cache pdx-read-serialized="true"/>

或者,您可以将属性设置为 对于 Apache Geode 缓存客户端应用程序, 如下:​​pdx-read-serialized​​​​true​

<gfe:client-cache pdx-read-serialized="true"/>

这样做会导致从缓存(即区域)读取所有值以及在客户端和服务器之间传递的信息 (或对等方)保持序列化形式,包括但不限于函数参数。

Apache Geode 仅序列化您专门配置(注册)的应用程序域对象类型 通过使用Apache Geode的ReflectionBasedAutoSerializer, 或特别(并推荐)使用“自定义”Apache GeodePdxSerializer。 如果你将Spring Data用于Apache Geode的Repository扩展,你甚至可能要考虑将Spring Data用于Apache Geode的MappingPdxSerializer。 它使用实体的映射元数据来确定序列化的应用程序域对象中的数据 到 PDX 实例。

然而,不太明显的是,Apache Geode会自动处理Javatypes,而不管 它们是否被显式配置(即,向 a 注册, 使用正则表达式模式和参数或由“自定义”Apache Geode处理), 尽管 Java 枚举实现了。​​Enum​​​​ReflectionBasedAutoSerializer​​​​classes​​​​PdxSerializer​​​​java.io.Serializable​

因此,当您设置Apache Geode服务器时,Apache Geode功能。 (包括 Apache Geode 函数注释的 POJO 类的 Spring 数据)被注册,那么你可能会遇到令人惊讶的行为 调用函数时。​​pdx-read-serialized​​​​true​​​​Execution​

调用函数时,可以传递以下参数:

orderProcessingFunctions.process(new Order(123, customer, LocalDateTime.now(), items), OrderSource.ONLINE, 400);

但是,服务器上的 Apache Geode 函数会得到以下内容:

process(regionData, order:PdxInstance, :PdxInstanceEnum, 400);

已作为PDX 实例传递给函数。 同样,这一切都会发生,因为设置为 ,这在以下情况下可能是必要的 Apache Geode 服务器与多个不同的客户端(例如,Java 客户端的组合)交互 和本机客户端,例如 C/C++、C# 等)。​​Order​​​​OrderSource​​​​pdx-read-serialized​​​​true​

这与 Apache Geode 的强类型函数注释 POJO 类方法签名的 Spring Data 背道而驰,在那里你会 合理地期望应用程序域对象类型,而不是 PDX 序列化实例。

因此,Spring Data for Apache Geode 包括增强的函数支持,可自动转换 PDX 类型化方法参数 由 Function 方法的签名定义的所需应用程序域对象类型(参数类型)。

但是,这也要求您显式注册Apache Geodeon Apache Geode服务器。 其中注册并使用了 Apache Geode 函数注释的 POJO 的 Spring 数据,如以下示例所示:​​PdxSerializer​

<bean id="customPdxSerializer" class="x.y.z.gemfire.serialization.pdx.MyCustomPdxSerializer"/>

<gfe:cache pdx-serializer-ref="customPdxSerializeer" pdx-read-serialized="true"/>

或者,为了方便起见,您可以使用Apache Geode的ReflectionBasedAutoSerializer。当然,我们建议您在可能的情况下使用自定义维护 对序列化策略进行更精细的控制。​​PdxSerializer​

最后,Apache Geode 的 Spring Data 小心翼翼地不要转换你的函数参数,如果你一般地处理你的函数参数。 或作为Apache Geode的PDX类型之一,如下所示:

@GemfireFunction
public Object genericFunction(String value, Object domainObject, PdxInstanceEnum pdxEnum) {
// ...
}

Spring Data for Apache Geode 将 PDX 类型数据转换为相应的应用程序域类型,当且仅当相应的 应用程序域类型位于类路径上,函数注释的 POJO 方法需要它。

有关自定义的,组合的特定于应用程序的Apache Geodeas以及适当的示例 POJO 函数参数类型处理基于方法签名,请参阅 Apache Geode 的ClientCacheFunctionExecutionWithPdxIntegrationTest类的 Spring 数据。​​PdxSerializers​

12. 阿帕奇卢西恩集成

Apache Geode与Apache Lucene集成,让您 使用 Lucene 查询对存储在 Apache Geode 中的数据进行索引和搜索。基于搜索的查询还包括 对查询结果进行分页的功能。

此外,Spring Data for Apache Geode增加了对基于Spring Data Commons投影基础设施的查询投影的支持。 此功能允许根据应用程序的需要将查询结果投影到一流的应用程序域类型中。

必须先创建 Lucene,然后才能运行任何基于 Lucene 搜索的查询。A可以在Spring(Data for Apache Geode)XML配置中创建,如下所示:​​Index​​​​LuceneIndex​

<gfe:lucene-index id="IndexOne" fields="fieldOne, fieldTwo" region-path="/Example"/>

此外,Apache Lucene允许每个字段的分析器规范,并且可以如以下示例所示进行配置:

<gfe:lucene-index id="IndexTwo" lucene-service-ref="luceneService" region-path="/AnotherExample">
<gfe:field-analyzers>
<map>
<entry key="fieldOne">
<bean class="example.AnalyzerOne"/>
</entry>
<entry key="fieldTwo">
<bean class="example.AnalyzerTwo"/>
</entry>
</map>
</gfe:field-analyzers>
</gfe:lucene-index>

可以指定为顶级 Bean 定义,并使用属性引用 在嵌套元素中,如下所示:​​Map​​​​ref​​​​<gfe:field-analyzers>​​​​<gfe-field-analyzers ref="refToTopLevelMapBeanDefinition"/>​

Spring Data for Apache Geode'sAPI和SDG的XML命名空间还允许在创建时指定org.apache.geode.cache.lucene.LuceneSerializer。允许您配置对象的转换方式 到 Lucene 文档,以便在为对象编制索引时编制索引。​​LuceneIndexFactoryBean​​​​LuceneIndex​​​​LuceneSerializer​

以下示例演示如何添加 anto:​​LuceneSerializer​​​​LuceneIndex​

<bean id="MyLuceneSerializer" class="example.CustomLuceneSerializer"/>

<gfe:lucene-index id="IndexThree" lucene-service-ref="luceneService" region-path="/YetAnotherExample">
<gfe:lucene-serializer ref="MyLuceneSerializer">
</gfe:lucene-index>

您也可以指定为匿名的嵌套 Bean 定义,如下所示:​​LuceneSerializer​

<gfe:lucene-index id="IndexThree" lucene-service-ref="luceneService" region-path="/YetAnotherExample">
<gfe:lucene-serializer>
<bean class="example.CustomLuceneSerializer"/>
</gfe:lucene-serializer>
</gfe:lucene-index>

或者,您可以在 a 类中声明或定义 Spring Java 配置, 如以下示例所示:​​LuceneIndex​​​​@Configuration​

@Bean(name = "Books")
@DependsOn("bookTitleIndex")
PartitionedRegionFactoryBean<Long, Book> booksRegion(GemFireCache gemfireCache) {

PartitionedRegionFactoryBean<Long, Book> peopleRegion =
new PartitionedRegionFactoryBean<>();

peopleRegion.setCache(gemfireCache);
peopleRegion.setClose(false);
peopleRegion.setPersistent(false);

return peopleRegion;
}

@Bean
LuceneIndexFactoryBean bookTitleIndex(GemFireCache gemFireCache,
LuceneSerializer luceneSerializer) {

LuceneIndexFactoryBean luceneIndex = new LuceneIndexFactoryBean();

luceneIndex.setCache(gemFireCache);
luceneIndex.setFields("title");
luceneIndex.setLuceneSerializer(luceneSerializer);
luceneIndex.setRegionPath("/Books");

return luceneIndex;
}

@Bean
CustomLuceneSerializer myLuceneSerialier() {
return new CustomeLuceneSerializer();
}

Apache Geode的Apache Lucene集成和支持有一些限制。

首先,acan 只能在 Apache GeodeRegion 上创建。​​LuceneIndex​​​​PARTITION​

第二,所有事物都必须在所适用的地区之前创建。​​LuceneIndexes​​​​LuceneIndex​

帮助确保在 Spring 容器中声明的所有定义都在区域之前创建 它们所适用的可持续发展目标包括。 您可以使用在XML配置中注册此SpringBeanFactoryPostProcessor​。 只能在使用 SDG XML 配置时使用。 有关Spring'scan的更多详细信息,请点击此处​。​​LuceneIndexes​​​​org.springframework.data.gemfire.config.support.LuceneIndexRegionBeanFactoryPostProcessor​​​​<bean class="org.springframework.data.gemfire.config.support.LuceneIndexRegionBeanFactoryPostProcessor"/>​​​​o.s.d.g.config.support.LuceneIndexRegionBeanFactoryPostProcessor​​​​BeanFactoryPostProcessors​

这些Apache Geode限制可能不适用于未来的版本,这就是为什么 SDGAPI也直接提到了该地区, 而不仅仅是区域路径。​​LuceneIndexFactoryBean​

当您想在以后使用数据定义现有区域时,这更理想 在应用程序的生命周期内,并根据需求需求。在可能的情况下,可持续发展目标努力坚持 强类型对象。但是,目前,您必须使用属性来指定区域 适用于哪个。​​LuceneIndex​​​​regionPath​​​​LuceneIndex​

此外,在前面的示例中,请注意 Spring 的注释的存在 在区域 Bean 定义上。这将创建从区域 bean 到 thebean 定义的依赖关系,确保在应用它的区域之前创建。​​@DependsOn​​​​Books​​​​Books​​​​bookTitleIndex​​​​LuceneIndex​​​​LuceneIndex​

现在,一旦我们有了,我们就可以执行基于 Lucene 的数据访问操作,例如查询。​​LuceneIndex​

12.1. Lucene 模板数据访问器

Spring Data for Apache Geode 为 Lucene 数据访问操作提供了两个主要模板,具体取决于级别低低 您的应用程序已准备好处理。

该接口通过使用 Apache GeodeLucene 类型定义查询操作, 在以下接口定义中定义:​​LuceneOperations​

public interface LuceneOperations {

<K, V> List<LuceneResultStruct<K, V>> query(String query, String defaultField [, int resultLimit]
, String... projectionFields);

<K, V> PageableLuceneQueryResults<K, V> query(String query, String defaultField,
int resultLimit, int pageSize, String... projectionFields);

<K, V> List<LuceneResultStruct<K, V>> query(LuceneQueryProvider queryProvider [, int resultLimit]
, String... projectionFields);

<K, V> PageableLuceneQueryResults<K, V> query(LuceneQueryProvider queryProvider,
int resultLimit, int pageSize, String... projectionFields);

<K> Collection<K> queryForKeys(String query, String defaultField [, int resultLimit]);

<K> Collection<K> queryForKeys(LuceneQueryProvider queryProvider [, int resultLimit]);

<V> Collection<V> queryForValues(String query, String defaultField [, int resultLimit]);

<V> Collection<V> queryForValues(LuceneQueryProvider queryProvider [, int resultLimit]);
}

指示参数是可选的。​​[, int resultLimit]​​​​resultLimit​

接口中的操作与 Apache Geode 的LuceneQuery接口提供的操作相匹配。 然而,SDG具有将专有的Apache Geode或Apache Lucene翻译成Spring高度一致和富有表现力的DAO异常层次结构的附加值, 特别是当许多现代数据访问操作涉及多个存储或存储库时。​​LuceneOperations​​​​Exceptions​

此外,SDG 的接口可以保护您的应用程序免受接口中断更改的影响 由底层 Apache Geode 或 Apache Lucene API 引入。​​LuceneOperations​

但是,提供仅使用Apache Geode和Apache Lucene的Lucene数据访问对象(DAO)将是可悲的。 数据类型(如 Apache Geode 的)。因此,SDG为您提供了解决这些重要应用问题的界面。以下列表显示 接口定义:​​LuceneResultStruct​​​​ProjectingLuceneOperations​​​​ProjectingLuceneOperations​

public interface ProjectingLuceneOperations {

<T> List<T> query(String query, String defaultField [, int resultLimit], Class<T> projectionType);

<T> Page<T> query(String query, String defaultField, int resultLimit, int pageSize, Class<T> projectionType);

<T> List<T> query(LuceneQueryProvider queryProvider [, int resultLimit], Class<T> projectionType);

<T> Page<T> query(LuceneQueryProvider queryProvider, int resultLimit, int pageSize, Class<T> projectionType);
}

该接口主要使用允许您使用的应用程序域对象类型 您的应用程序数据。方法变体接受投影类型,模板应用查询结果 通过使用 Spring 数据共享投影基础设施到给定投影类型的实例。​​ProjectingLuceneOperations​​​​query​

此外,该模板将分页的 Lucene 查询结果包装在 Spring 数据共享抽象的实例中。相同的投影逻辑仍可应用于页面中的结果,并且是延迟投影的 当访问集合中的每个页面时。​​Page​

例如,假设您有一个表示 a 的类,如下所示:​​Person​

class Person {

Gender gender;

LocalDate birthDate;

String firstName;
String lastName;

...

String getName() {
return String.format("%1$s %2$s", getFirstName(), getLastName());
}
}

此外,您可能有一个界面来表示人员,具体取决于您的应用程序视图, 如下:​​Customers​

interface Customer {

String getName()

}

如果我定义以下内容...​​LuceneIndex​

@Bean
LuceneIndexFactoryBean personLastNameIndex(GemFireCache gemfireCache) {

LuceneIndexFactoryBean personLastNameIndex =
new LuceneIndexFactoryBean();

personLastNameIndex.setCache(gemfireCache);
personLastNameIndex.setFields("lastName");
personLastNameIndex.setRegionPath("/People");

return personLastNameIndex;
}

然后,您可以查询人员作为对象,如下所示:​​Person​

List<Person> people = luceneTemplate.query("lastName: D*", "lastName", Person.class);

或者,您可以查询 aof 类型,如下所示:​​Page​​​​Customer​

Page<Customer> customers = luceneTemplate.query("lastName: D*", "lastName", 100, 20, Customer.class);

然后,可以使用 Thecan 获取结果的各个页面,如下所示:​​Page​

List<Customer> firstPage = customers.getContent();

方便的是,Spring Data Commons接口也实现了,使其变得容易 以循环访问内容。​​Page​​​​java.lang.Iterable<T>​

对Spring Data Commons Projecting基础设施的唯一限制是投影类型必须是 一个接口。但是,可以扩展提供的 SDC 投影基础结构,并提供自定义投影工厂,该工厂使用CGLIB生成代理类作为投影实体。

您可以使用 Lucene 模板设置自定义。​​setProjectionFactory(:ProjectionFactory)​​​​ProjectionFactory​

12.2. 注释配置支持

最后,Spring Data for Apache Geode 提供了注释配置支持。​​LuceneIndexes​

最终,SDG Lucene支持将进入存储库基础架构扩展 Apache Geode,以便Lucene查询可以表示为应用程序接口上的方法, 与今天的OQL 支持大致相同。​​Repository​

但是,与此同时,如果您想方便地表达,您可以直接在 应用程序域对象,如以下示例所示:​​LuceneIndexes​

@PartitionRegion("People")
class Person {

Gender gender;

@Index
LocalDate birthDate;

String firstName;

@LuceneIndex;
String lastName;

...
}

要启用此功能,您必须将 SDG 的注释配置支持专门用于注释,如下所示:​​@EnableEntityDefineRegions​​​​@EnableIndexing​

@PeerCacheApplication
@EnableEntityDefinedRegions
@EnableIndexing
class ApplicationConfiguration {

...
}

​LuceneIndexes​​​只能在Apache Geode服务器上创建,因为仅适用于 到区域。​​LuceneIndexes​​​​PARTITION​

鉴于我们之前对类的定义,SDG 注释配置支持发现 实体类定义并确定人员存储在称为“人员”的区域中 并且有一个OQ与aon一起。​​Person​​​​Person​​​​PARTITION​​​​Person​​​​Index​​​​birthDate​​​​LuceneIndex​​​​lastName​

13. 在 Apache Geode 中引导 Spring 应用程序上下文

通常,基于 Spring 的应用程序通过使用 Spring Data 来实现Apache Geode 的功能来引导 Apache Geode。 通过指定使用 Spring Data for Apache Geode XML 命名空间的元素,单个嵌入式 Apache Geode 对等实例在与应用程序相同的 JVM 进程中使用默认设置创建和初始化。<gfe:cache/>Cache

但是,有时有必要(可能是您的 IT 组织强加的要求)Apache Geode 由提供的Apache Geode工具套件完全管理和操作,也许使用Gfsh。通过使用Gfsh,Apache Geode引导程序 你的春天而不是相反。而不是应用程序服务器或 Java 主类 使用Spring Boot,Apache Geode进行引导并托管您的应用程序。​​ApplicationContext​

Apache Geode 不是应用程序服务器。此外,使用此方法存在局限性 其中涉及Apache Geode缓存配置。

13.1. 使用 Apache Geode 引导从 Gfsh 开始的 Spring 上下文

为了在启动Apache Geode服务器时引导Springin Apache Geode 使用Gfsh,您必须使用 Apache Geode 的发起器​功能。 初始值设定项块可以声明在缓存初始化后启动的应用程序回调 作者:Apache Geode。ApplicationContext

初始值设定项在初始值设定项​元素中声明 通过使用Apache Geode本机的最小片段。要引导弹簧, afile 是必需的,就像引导需要 Spring XML 配置的最小片段一样。 a 弹簧配置有组件扫描功能 (例如)。cache.xmlApplicationContextcache.xmlApplicationContext<context:component-scan base-packages="…"/>

幸运的是,框架已经方便地提供了这样的初始值设定项:SpringContextBootstrappingInitializer。

以下示例显示了 Apache Geode 文件中此类的典型但最小的配置:​​cache.xml​

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

<initializer>
<class-name>org.springframework.data.gemfire.support.SpringContextBootstrappingInitializer</class-name>
<parameter name="contextConfigLocations">
<string>classpath:application-context.xml</string>
</parameter>
</initializer>

</cache>

Theclass 遵循类似于 Spring 的 Springs 类的约定,后者用于在 Web 应用程序内引导 Spring,其中配置文件使用 Servlet 上下文参数指定。​​SpringContextBootstrappingInitializer​​​​ContextLoaderListener​​​​ApplicationContext​​​​ApplicationContext​​​​contextConfigLocations​

此外,该类还可以与参数一起使用 指定包含适当批注的应用程序组件的基本包的逗号分隔列表。 Spring 容器搜索这些组件以查找和创建 Spring bean 和其他应用程序组件 在类路径中,如以下示例所示:​​SpringContextBootstrappingInitializer​​​​basePackages​

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

<initializer>
<class-name>org.springframework.data.gemfire.support.SpringContextBootstrappingInitializer</class-name>
<parameter name="basePackages">
<string>org.mycompany.myapp.services,org.mycompany.myapp.dao,...</string>
</parameter>
</initializer>

</cache>

然后,将正确配置和构造的文件(如前所示)指定为 在Gfsh 中启动 Apache Geode 服务器时的命令行选项,命令行如下所示:​​CLASSPATH​​​​cache.xml​

gfsh>start server --name=ExampleServer --log-level=config ...
--classpath="/path/to/application/classes.jar:/path/to/spring-data-geode-<major>.<minor>.<maint>.RELEASE.jar"
--cache-xml-file="/path/to/geode/cache.xml"

可以是任何有效的 Spring 配置元数据,包括所有 SDG XML 命名空间元素。这种方法的唯一限制是无法配置Apache Geode缓存 通过使用 SDG XML 命名空间。换句话说,没有任何元素属性 (如,,,,, 和其他)可以指定。如果使用,将忽略这些属性。​​application-context.xml​​​​<gfe:cache/>​​​​cache-xml-location​​​​properties-ref​​​​critical-heap-percentage​​​​pdx-serializer-ref​​​​lock-lease​

原因是 Apache Geode 本身已经在初始值设定项之前创建并初始化了缓存。 被调用。因此,缓存已经存在,并且由于它是“单例”,因此无法重新初始化 或增强其任何配置。

13.2. 懒线 Apache Geode 组件

Spring Data for Apache Geode 已经支持自动连接 Apache Geode 组件(例如,等),这些组件由 Apache Geode 使用 SDG 的类,如使用自动连线和注释的配置中所述。但是,这有效 只有当 Spring 是进行引导的人时(也就是说,当 Spring 引导 Apache Geode 时)。​​CacheListeners​​​​CacheLoaders​​​​CacheWriters​​​​cache.xml​​​​WiringDeclarableSupport​

当您的 Springis 由 Apache Geode 引导时,这些 Apache Geode 应用程序组件 不被注意,因为春天还不存在。春天没有得到 创建直到 Apache Geode 调用初始值设定项块,这仅在所有其他 Apache Geode 之后发生 组件(缓存、区域等)已创建并初始化。​​ApplicationContext​​​​ApplicationContext​​​​ApplicationContext​

为了解决这个问题,引入了一个新类。这个新类知道 春天。这个抽象基类背后的意图是任何实现类寄存器 本身由 Spring 容器配置,该容器最终由 Apache Geode 在初始值设定项创建后创建 被称为。从本质上讲,这使您的Apache Geode应用程序组件有机会进行配置和自动连接。 使用弹簧容器中定义的春豆。​​LazyWiringDeclarableSupport​​​​ApplicationContext​

为了使您的 Apache Geode 应用程序组件由 Spring 容器自动连接,您应该创建 一个应用程序类,用于扩展和批注任何需要 作为 Spring Bean 依赖项提供,类似于以下示例:​​LazyWiringDeclarableSupport​

public class UserDataSourceCacheLoader extends LazyWiringDeclarableSupport
implements CacheLoader<String, User> {

@Autowired
private DataSource userDataSource;

...
}

如上例所示,您可能必须(尽管很少)同时定义了区域 和阿帕奇·乔德中的组件。可能需要访问应用程序 存储库(或者可能是在 Spring 中定义的 JDBC)用于加载到 启动时的Apache GeodeRegion。​​CacheLoader​​​​CacheListener​​​​cache.xml​​​​CacheLoader​​​​DataSource​​​​ApplicationContext​​​​Users​​​​REPLICATE​

谨慎

以这种方式将Apache Geode和Spring容器的不同生命周期混合在一起时要小心。 并非所有用例和方案都受支持。Apache Geode配置将类似于 以下内容(来自SDG的测试套件):​​cache.xml​

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

<region name="Users" refid="REPLICATE">
<region-attributes initial-capacity="101" load-factor="0.85">
<key-constraint>java.lang.String</key-constraint>
<value-constraint>org.springframework.data.gemfire.repository.sample.User</value-constraint>
<cache-loader>
<class-name>
org.springframework.data.gemfire.support.SpringContextBootstrappingInitializerIntegrationTests$UserDataStoreCacheLoader
</class-name>
</cache-loader>
</region-attributes>
</region>

<initializer>
<class-name>org.springframework.data.gemfire.support.SpringContextBootstrappingInitializer</class-name>
<parameter name="basePackages">
<string>org.springframework.data.gemfire.support.sample</string>
</parameter>
</initializer>

</cache>

14. 示例应用程序

示例应用程序现在在Spring Apache Geode示例存储库中维护。

Spring Data for Apache Geode 项目还包括一个示例应用程序。名为“Hello World”的示例应用程序 演示如何在 Spring 应用程序中配置和使用 Apache Geode。在运行时,示例提供 一个 shell,允许您对数据网格运行各种命令。它提供了一个优秀的 对于不熟悉基本组件或不熟悉Spring和Apache Geode概念的开发人员的起点。

该示例与发行版捆绑在一起,并且基于 Maven。您可以将其导入任何 Maven 感知 IDE(例如Spring 工具套件)或从命令行运行它们。

14.1. 你好世界

“Hello World”示例应用程序演示了 Spring Data for Apache Geode 项目的核心功能。 它引导Apache Geode,对其进行配置,对缓存执行任意命令,然后将其关闭 当应用程序退出时。可以同时启动应用程序的多个实例 协同工作,无需任何用户干预即可共享数据。

在 Linux 下运行

如果在启动 Apache Geode 或示例时遇到网络问题,请尝试添加以下内容 系统属性到命令行(例如,)。 有关替代(全局)修复(特别是在 Ubuntu 上),请参阅SGF-28​。​​java.net.preferIPv4Stack=true​​​​-Djava.net.preferIPv4Stack=true​

14.1.1. 启动和停止示例

“Hello World”示例应用程序被设计为一个独立的 Java 应用程序。它具有可以启动的类 从 IDE(在 Eclipse 或 STS 中,通过)或从命令行 通过马文。如果类路径设置正确,还可以直接在生成的工件上使用。​​main​​​​Run As/Java Application​​​​mvn exec:java​​​​java​

要停止示例,请在命令行中键入或按停止 JVM 并关闭 弹簧容器。​​exit​​​​Ctrl+C​

14.1.2. 使用示例

启动后,该示例将创建一个共享数据网格,并允许您针对它发出命令。 输出应类似于以下内容:

INFO: Created {data-store-name} Cache [Spring {data-store-name} World] v. X.Y.Z
INFO: Created new cache region [myWorld]
INFO: Member xxxxxx:50694/51611 connecting to region [myWorld]
Hello World!
Want to interact with the world ? ...
Supported commands are:

get <key> - retrieves an entry (by key) from the grid
put <key> <value> - puts a new entry into the grid
remove <key> - removes an entry (by key) from the grid
...

例如,若要向网格添加新项,可以使用以下命令:

-> Bold Section qName:emphasis level:5, chunks:[put 1 unu] attrs:[role:bold]
INFO: Added [1=unu] to the cache
null
-> Bold Section qName:emphasis level:5, chunks:[put 1 one] attrs:[role:bold]
INFO: Updated [1] from [unu] to [one]
unu
-> Bold Section qName:emphasis level:5, chunks:[size] attrs:[role:bold]
1
-> Bold Section qName:emphasis level:5, chunks:[put 2 two] attrs:[role:bold]
INFO: Added [2=two] to the cache
null
-> Bold Section qName:emphasis level:5, chunks:[size] attrs:[role:bold]
2

可以同时运行多个实例。启动后,新 VM 会自动看到现有区域 及其信息,如以下示例所示:

INFO: Connected to Distributed System ['Spring {data-store-name} World'=xxxx:56218/49320@yyyyy]
Hello World!
...

-> Bold Section qName:emphasis level:5, chunks:[size] attrs:[role:bold]
2
-> Bold Section qName:emphasis level:5, chunks:[map] attrs:[role:bold]
[2=two] [1=one]
-> Bold Section qName:emphasis level:5, chunks:[query length = 3] attrs:[role:bold]
[one, two]

我们鼓励您试验该示例,根据需要启动(和停止)任意数量的实例,并在一个实例中运行各种命令 看看其他人的反应。若要保留数据,至少需要一个实例始终处于活动状态。如果所有实例 关闭,网格数据被完全破坏。

14.1.3. 你好世界示例说明

“Hello World”示例使用Spring XML和注释进行配置。初始引导配置是,其中包括文件中定义的缓存配置 并对 Spring 组件执行类路径组件扫描。​​app-context.xml​​​​cache-context.xml​

缓存配置定义了 Apache Geode 缓存,一个区域,为了便于说明,它充当记录器。​​CacheListener​

主要的豆子是和,它依靠the来相互作用 分布式结构。这两个类都使用注释来定义它们的依赖关系和生命周期回调。​​HelloWorld​​​​CommandProcessor​​​​GemfireTemplate​


标签:String,Spring,Geode,Apache,org,属性
From: https://blog.51cto.com/u_15326439/5878309

相关文章

  • Spring事务
    1什么是事务?事务(Transaction)是数据库区别于文件系统的重要特性之一。目前国际认可的数据库设计原则是ACID特性,用以保证数据库事务的正确执行。Mysql的innodb引擎中的事务......
  • Apache Geode 的 Spring Data(数据)(三)
    6.12.4.配置过期与逐出一起,过期还可用于管理内存允许存储在区域中的条目过期。ApacheGeode同时支持生存时间(TTL)和空闲超时(TTI)条目过期策略。SpringDataforApacheG......
  • SpringBoot
    AOP@EnableAspectJAutoProxy@Aspect@Pointcut@Before@After@Around@AfterThrowing@AfterReturning配置文件参数自动转List类型参数自动转为List@Value("#{'${c......
  • Spring Cloud Feign 压缩配置导致的字符混乱(only regular white space )
     [nio-9601-exec-2].w.s.m.s.DefaultHandlerExceptionResolver:Resolved[org.springframework.http.converter.HttpMessageNotReadableException:JSONparseerro......
  • Apache Geode 的 Spring Data(数据)(二)
    6.使用注释使用弹簧容器引导ApacheGeodeSpringDataforApacheGeode(SDG)2.0引入了一个新的基于注释的配置模型使用Spring容器配置和引导ApacheGeode。引入基于......
  • idea中springboot项目的application.properties没效果
    从svn中拉的源码, .idea文件夹没上传到svn, 拉下来后resources目录下的application.properties不起作用, 还是默认使用8080端口启动, 在resources目录上面右击, 选择......
  • Apache Geode 的 Spring Data(数据)
    版本2.7.6SpringDataforApacheGeode专注于集成SpringFramework强大的非侵入式编程模型。以及使用ApacheGeode简化Java应用程序的配置和开发的概念当使用Apache......
  • 在linu系统安装apache全过程(httpd、apr、apr-util、pcre)以及进行相应配置
    1.下载安装包,需要下面3个安装包[root@bes2apache]#ll总用量8520-rw-r--r--.1rootroot10208339月1817:47apr-1.5.1.tar.gz-rw-r--r--.1rootroot8744629月......
  • Apache Cassandra 的 Spring Data(数据)
    版本4.0.0SpringDataforApacheCassandra项目将核心Spring概念应用于使用CassandraColumnar数据存储开发解决方案。“模板”作为存储和查询文档的高级抽象提供。......
  • Apache Cassandra 的 Spring Data(数据)(二)
    8.简介参考文档的这一部分解释了SpringDataforApacheCassandra提供的核心功能。CassandraSupport引入了Cassandra模块功能集。反应式Cassandra支持解释了反应式......