首页 > 解决方案 > 如何在 Spring Data GemFire/Geode 中配置要写入动态区域的数据

问题描述

我已经在 GemFire 中创建了多个区域。我想根据请求将一般数据写入到区域userregionemloyee区域(我还有几个区域)。在 Controller 中,它接收到一个通用请求,因此它必须从请求中识别出要选择哪个现有 Region。

@Region(value="UserRegion")
public class GeneralData implements Serializable {

由于Region名称是注释的,那么如何从Controller中设置Region名称。

标签: spring-bootspring-datageodespring-data-gemfire

解决方案


您似乎在问是否可以根据请求在运行时动态确定区域,例如来自Spring [Web]的请求@Controller

也许,类似于PR #91中的要求?虽然,我拒绝了这个 PR 以支持更灵活的方法,命名为DATAGEODE-244 -“添加 RegionResolver 接口以在需要时/在需要时启用惰性区域解析。

虽然,你的问题有点模棱两可,我不想在这里假设任何事情。

几点...

1) 首先,应用程序域对象(例如GeneralDataEmployee)确实被持久化到特定的、明确声明的区域 wrt 以“映射”(即使用 SDG @Region映射”注释),正如Spring Data Repository抽象所解析的那样。这与任何其他映射技术(例如 ORM;使用 Hibernate 的 JPA)实际上并没有什么不同。

默认情况下,如果@Region未指定映射注解,则 SD[G] 将使用应用程序域对象类型的简单类名(例如“Employee”)来解析对象将被持久化的 Region。通常,最好是明确的,并使用Spring Data [GemFire]映射注释声明您的意图(例如@Region,或@Id标记标识符等)。

2) 其次,当然,这一切都取决于您是否首先使用Spring Data [GemFire] Repository 基础设施。如果不是,那么上述观点是没有意义的。如果你是那么,我想你想要这样的东西......

@Region("Employees")
class Employee { ... }

@Controller
class MyController {

  @Autowired
  private EmployeeRepository employeeRepository;

  @PostMapping("/employees")
  public String process(Employee employee) {

    // modify employee, then save...

    if (employee.isContractor()) {
      // save to "Contractors" Region
    }
    else {
      employeeRepository.save(employee);
    }
  }
}

当然,您不能使用EmployeeRepository来保存 Employee 对象(它被映射到“Employees”区域到“Contractors”区域,因为Employee类型是使用“@Region”映射注释“映射”到“Employees”区域。

SDG 确实在前一段时间添加了支持,现在允许用户使用@Region映射注释来注释存储库接口,例如......

@Region("Contractors")
interface ContractorRepository extends CrudRepository<Employee, Long> { ... }

这将有效地覆盖@Region应用程序域对象类型(例如Employee)上的@Region映射注释,并改为使用 Repo 上的映射注释。这允许用户对相同的应用程序域对象类型具有不同的存储库(接口)声明,以便将域对象映射到不同的区域。

尽管如此,如果您有很多不同的 Region 和基于请求的动态逻辑,那么为每个潜在目的地都有一个 Repository 接口声明,这仍然很麻烦。

或者,您可以HttpMessageConverters在 Spring Web MVC 配置中注册不同的 Spring,以根据数据所属的位置将请求数据转换为Contractor确定其持久目的地的(实体)类型(例如)。

@Region("Contractors")
class Contractor extends Employee { ... }

然后:

@PostMapping("/employees")
public void process(Contractor contractor) {

  // modify contractor, then save...

  this.employeeRepository.save(contractor);
}

3)第三,当然,如果您不使用Spring Data Repository抽象(和 SDG 扩展),那么您可以通过使用 SDG 的GemfireTemplate.

例如:

@Region("Employees")
class Employee { .. }

@Region("Contractors")
class Contractor extends Employee { ... }

@Configuration
@ClientCacheApplication
class GemFireConfiguration {

  @Bean("Employees")
  ClientRegionFactoryBean employeesRegion(ClientCache clientCache) { ... }

  @Bean("Contractors")
  ClientRegionFactoryBean contractorsRegion(ClientCache clientCache) { ... }

  @Bean("employeesTemplate) {
  GemfireTemplate employeesTemplate(ClientCache clientCache) {
    return new GemfireTemplate(clientCache.getRegion("/Employees"));
  }

  @Bean("contractorsTemplate) {
  GemfireTemplate contractorsTemplate(ClientCache clientCache) {
    return new GemfireTemplate(clientCache.getRegion("/Contractors"));
  }
}


@Controller
class MyController {

  @Autowired
  @Qualifier("employeeTemplate")
  private GemfireTemplate employeesTemplate;

  @Autowired
  @Qualifier("contractorsTemplate")
  private GemfireTemplate contractorsTemplate;

  @PostMapping("/employees")
  public void process(Employee employee) {

    // modify the employee, then save...

    if (employee.isContractor()) {
      constractorsTemplate.put(employee.getId(), employee);
    else {
      employeesTemplate.put(employee.getId(), employee);
    }
  }
}

当然,您可能会想出一种更有创意的方式来“解决”基于使用策略模式或类似效果的请求的需要哪个模板。

如果我正确理解您的 UC,那么DATAGEODE-244应该在不久的将来提供一些缓解,一旦它相对于其他正在进行的工作(实际上很快)被优先考虑。

我会说,我并不是真正喜欢根据请求类型动态更改持久位置。每个实体都经过精心设计,以映射到特定的目标持久存储。

此外,并不是这里的情况(至少我认为不是),我也不是“垃圾”区域的粉丝,即存储多种“类型”数据的区域。这对于查询来说不是最优的,这可能是为什么要将单个应用程序域类型持久化到不同区域的一个论点,因为这些区域可能会针对不同类型的查询(使用索引)和/或事件进行调整。

无论如何,希望这个答案能提供一些方向或想法,直到DATAGEODE-244准备好。

干杯!


推荐阅读