未使用spring-cache设置GemFire条目生存时间

时间:2017-11-08 19:26:22

标签: java spring-boot gemfire spring-cache spring-data-gemfire

以下是成功地将数据保存在远程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;
    }

}

1 个答案:

答案 0 :(得分:1)

只是好奇你认为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定义方法参数(即injectTimeoutInSecs),如此...

@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),以根据属性占位符动态调整定位器主机和端口配置。

  • 我定义了一个PropertySourcesPlaceholderConfigurer来处理整个Spring,基于Java的配置元数据中@Value注释中使用的属性占位符。

  • 我还使用了新的@EnableGemfireCaching注释,它取代了显式定义gemfireCacheManager bean定义的需要。它还支持Spring的缓存抽象(为您指定@EnableCaching)。

无论如何,SDG的 Annotation-based configuration model让您更轻松地完成所有事情。但同样,你需要在 Pivotal GemFire 9.1.x 中使用 Spring Data GemFire 2.0+(SD Kay)

希望这有帮助!

-John