以下是成功将数据持久保存在远程GemFire群集中并成功保持本地spring-cache更新的代码段。但是,当我尝试使用ExpirationAttributes时,条目没有按预期的方式销毁。我已经提到了this和相关链接。任何建议都会有所帮助!

import org.springframework.data.gemfire.ExpirationActionType;
import org.springframework.data.gemfire.ExpirationAttributesFactoryBean;
import org.springframework.data.gemfire.RegionAttributesFactoryBean;
import org.springframework.data.gemfire.client.ClientCacheFactoryBean;
import org.springframework.data.gemfire.client.ClientRegionFactoryBean;
import org.springframework.data.gemfire.support.ConnectionEndpoint;
import org.springframework.data.gemfire.support.GemfireCacheManager;

import com.gemstone.gemfire.cache.ExpirationAttributes;
import com.gemstone.gemfire.cache.RegionAttributes;
import com.gemstone.gemfire.cache.client.ClientCache;
import com.gemstone.gemfire.cache.client.ClientRegionShortcut;
import com.gemstone.gemfire.pdx.ReflectionBasedAutoSerializer;

@Configuration
@Profile("local")
public class GemFireCachingConfig {

    @Bean
    Properties gemfireProperties(...) {

        //Sets gemfire properties and return
        return gemfireProperties;
    }

    @Bean
    @Primary
    ReflectionBasedAutoSerializer reflectionBasedAutoSerializer() {
        return new ReflectionBasedAutoSerializer("pkg.containing.cacheable.object");
    }

    @Bean
    @Primary
    ClientCacheFactoryBean clientCacheFactory(String injectedGemFirehost,
            int injectedGemfirePort, Properties gemfireProperties,
            ReflectionBasedAutoSerializer reflectionBasedAutoSerializer) {

        ClientCacheFactoryBean cachefactoryBean = new ClientCacheFactoryBean();
        cachefactoryBean.setProperties(gemfireProperties);
        cachefactoryBean.setClose(true);
        cachefactoryBean.setPdxSerializer(reflectionBasedAutoSerializer);
        cachefactoryBean.setPdxReadSerialized(false);
        cachefactoryBean.setPdxIgnoreUnreadFields(true);

        ConnectionEndpoint[] locators = new ConnectionEndpoint[1];
        locators[0] = new ConnectionEndpoint(injectedGemFirehost, injectedGemfirePort);
        cachefactoryBean.setLocators(locators);

        return cachefactoryBean;

    }


    @Bean
    public ExpirationAttributesFactoryBean entryTtlExpirationAttributes(
            int injectedTimeoutInSecs) {

        ExpirationAttributesFactoryBean expirationAttributes = new ExpirationAttributesFactoryBean();

        expirationAttributes.setAction(ExpirationActionType.DESTROY.getExpirationAction());
        expirationAttributes.setTimeout(injectedTimeoutInSecs);

        return expirationAttributes;
    }

    @Bean
    @Autowired
    public RegionAttributesFactoryBean regionAttributes(
            @Qualifier("entryTtlExpirationAttributes") ExpirationAttributes entryTtl) {

        RegionAttributesFactoryBean regionAttributes = new RegionAttributesFactoryBean();
        regionAttributes.setStatisticsEnabled(true);
        regionAttributes.setEntryTimeToLive(entryTtl);

        return regionAttributes;
    }

    @Bean
    @Primary
    ClientRegionFactoryBean<String, Object> regionFactoryBean(ClientCache gemfireCache,
            @Qualifier("regionAttributes") RegionAttributes<String, Object> regionAttributes) {

        ClientRegionFactoryBean<String, Object> regionFactoryBean = new ClientRegionFactoryBean<>();

        regionFactoryBean.setAttributes(regionAttributes);
        regionFactoryBean.setCache(gemfireCache);
        regionFactoryBean.setClose(false);
        regionFactoryBean.setPersistent(false);
        regionFactoryBean.setRegionName(regionName);
        regionFactoryBean.setShortcut(ClientRegionShortcut.CACHING_PROXY_HEAP_LRU);

        return regionFactoryBean;
    }

    @Bean
    GemfireCacheManager cacheManager(ClientCache gemfireCache) {
        GemfireCacheManager cacheManager = new GemfireCacheManager();
        cacheManager.setCache(gemfireCache);

        return cacheManager;
    }

}

最佳答案

只是好奇您如何认为injectedTimeoutInSeconds是如何在Spring配置中“注入”到entryTtlExpirationAttributes bean定义中的?这个...

@Bean
public ExpirationAttributesFactoryBean entryTtlExpirationAttributes(
        int injectedTimeoutInSecs) {

    ExpirationAttributesFactoryBean expirationAttributes =
        new ExpirationAttributesFactoryBean();

    expirationAttributes.setAction(
        ExpirationActionType.DESTROY.getExpirationAction());
    expirationAttributes.setTimeout(injectedTimeoutInSecs);

    return expirationAttributes;
}


您需要使用Spring的entryTtlExpirationAttributes注释来注释@Value bean定义方法参数(即,injectedTimeoutInSecs),就像这样...

@Bean
public ExpirationAttributesFactoryBean entryTtlExpirationAttributes(
        @Value("${gemfire.cache.expiration.ttl.timeout:600}")
            int injectedTimeoutInSecs) {


然后,在Spring Boot application.properties文件中,可以为属性(gemfire.cache.expiration.ttl.timeout)设置一个值。

#application.properties
gemfire.cache.expiration.ttl.timeout = 300


如果未显式设置属性,则@Value注释可以提供默认值。

@Value({${property:defaultValue}")

此外,您需要在Spring Java配置中提供propertySourcePlaceholderConfigurer bean定义,以使Spring能够“替换”属性占位符值...

@Bean
static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
    return new PropertySourcesPlaceholderConfigurer();
}


您可以看到与here上方类似的配置。

最后,您可以将整个Spring GemFire Java配置类简化为该类。

import java.util.Collections;

import org.apache.geode.cache.ExpirationAttributes;
import org.apache.geode.cache.GemFireCache;
import org.apache.geode.cache.RegionAttributes;
import org.apache.geode.cache.client.ClientRegionShortcut;
import org.apache.geode.pdx.ReflectionBasedAutoSerializer;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Primary;
import org.springframework.context.annotation.Profile;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.data.gemfire.RegionAttributesFactoryBean;
import org.springframework.data.gemfire.cache.config.EnableGemfireCaching;
import org.springframework.data.gemfire.client.ClientRegionFactoryBean;
import org.springframework.data.gemfire.config.annotation.ClientCacheApplication;
import org.springframework.data.gemfire.config.annotation.ClientCacheConfigurer;
import org.springframework.data.gemfire.config.annotation.EnablePdx;
import org.springframework.data.gemfire.expiration.ExpirationActionType;
import org.springframework.data.gemfire.expiration.ExpirationAttributesFactoryBean;
import org.springframework.data.gemfire.support.ConnectionEndpoint;

@ClientCacheApplication
@EnableGemfireCaching
@EnablePdx(ignoreUnreadFields = true, readSerialized = false,
  serializerBeanName = "reflectionBasedAutoSerializer")
@Profile("local")
public class GemFireCachingConfig {

  @Bean
  static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
    return new PropertySourcesPlaceholderConfigurer();
  }

  // NOTE: you can externalize Pivotal GemFire properties in a gemfire.properties file,
  // placed in the root of your application classpath.
  //
  // Alternatively, you can use Spring Boot's application.properties to set GemFire properties
  // using the corresponding Spring Data GemFire (annotation-based) property (e.g. spring.data.gemfire.cache.log-level)
  //
  // See here...
  // https://docs.spring.io/spring-data/gemfire/docs/current/api/org/springframework/data/gemfire/config/annotation/ClientCacheApplication.html#logLevel--

  @Bean
  @Primary
  ReflectionBasedAutoSerializer reflectionBasedAutoSerializer() {
    return new ReflectionBasedAutoSerializer("pkg.containing.cacheable.object");
  }

  @Bean
  ClientCacheConfigurer clientCacheHostPortConfigurer(
      @Value("gemfire.locator.host") String locatorHost,
      @Value("gemfire.locator.port") int locatorPort) {

    return (beanName, clientCacheFactoryBean) ->
      clientCacheFactoryBean.setLocators(Collections.singletonList(
        new ConnectionEndpoint(locatorHost, locatorPort)));
  }

  @Bean("RegionNameHere")
  ClientRegionFactoryBean<String, Object> regionFactoryBean(GemFireCache gemfireCache,
      @Qualifier("regionAttributes") RegionAttributes<String, Object> regionAttributes) {

    ClientRegionFactoryBean<String, Object> clientRegionFactory = new ClientRegionFactoryBean<>();

    clientRegionFactory.setAttributes(regionAttributes);
    clientRegionFactory.setCache(gemfireCache);
    clientRegionFactory.setClose(false);
    clientRegionFactory.setShortcut(ClientRegionShortcut.CACHING_PROXY_HEAP_LRU);

    return clientRegionFactory;
  }

  @Bean
  public RegionAttributesFactoryBean regionAttributes(
      @Qualifier("entryTtlExpirationAttributes") ExpirationAttributes expirationAttributes) {

    RegionAttributesFactoryBean regionAttributes = new RegionAttributesFactoryBean();

    regionAttributes.setStatisticsEnabled(true);
    regionAttributes.setEntryTimeToLive(expirationAttributes);

    return regionAttributes;
  }

  @Bean
  public ExpirationAttributesFactoryBean entryTtlExpirationAttributes(
      @Value("${gemfire.cache.expiration:600") int timeoutInSeconds) {

    ExpirationAttributesFactoryBean expirationAttributes = new ExpirationAttributesFactoryBean();

    expirationAttributes.setAction(ExpirationActionType.DESTROY.getExpirationAction());
    expirationAttributes.setTimeout(timeoutInSeconds);

    return expirationAttributes;
  }
}


当然,此配置基于Spring Data GemFire 2.0.1.RELEASE(Kay-SR1)。


注意@ClientCacheApplication批注,它替换了clientCacheFactory bean定义的需要。
我还使用了新的@EnablePdx注释来配置GemFire的PDX序列化行为。
我声明了一个ClientCacheConfigurer类型的bean定义(clientCacheHostPortConfigurer),以基于属性占位符动态调整Locator主机和端口配置。
我定义了一个PropertySourcesPlaceholderConfigurer来处理整个基于Java的Spring配置元数据中@Value批注中使用的属性占位符。
我还使用了新的@EnableGemfireCaching注释,该注释替换了显式定义gemfireCacheManager bean定义的需要。它还启用了Spring的Cache Abstraction(为您指定@EnableCaching)。


无论如何,SDG的新Annotation-based configuration model使其更易于执行所有操作。但是同样,您需要在Pivotal GemFire 9.1.x中使用Spring Data GemFire 2.0+(SD Kay)。

希望这可以帮助!

-约翰

10-06 14:50