代码之家  ›  专栏  ›  技术社区  ›  Nymeria

仅绑定到当前事务的Spring缓存

  •  1
  • Nymeria  · 技术社区  · 7 年前

    我正试图说服我的公司使用Spring3.2的缓存(我知道它很旧)。

    该应用程序构建在alfresco 5的顶部。x(构建在spring 3.2的顶部)。

    目前,我们有一些绑定到当前事务的缓存:

    if (AlfrescoTransactionSupport.getTransactionReadState() == TxnReadState.TXN_READ_ONLY) {
      cache = (Map<String, Boolean>) AlfrescoTransactionSupport.getResource(CACHED_NAME);
      if (cache == null) {
        cache = new HashMap<String, Boolean>();
      }
      AlfrescoTransactionSupport.bindResource(CACHED_NAME, cache);
    }
    

    缓存仅对当前读取事务有效,然后被销毁。

    我试过了

    @Cacheable("cache_name") 
    @Transactional(readOnly=true)
    

    注释,但当读写事务打开时,缓存不会被销毁。

    你知道怎么用春天的方式吗?

    2 回复  |  直到 7 年前
        1
  •  0
  •   Nymeria    7 年前

    @比亚曼是对的,

    我必须实现自己的缓存才能做到这一点。

    首先,我让ti实现BeanFactory:

    import org.springframework.beans.factory.BeanNameAware;
    import org.springframework.beans.factory.FactoryBean;
    import org.springframework.beans.factory.InitializingBean;
    import org.springframework.util.StringUtils;
    
    public class KReadTransactionCacheFactoryBean implements FactoryBean<KReadTransactionCache>, BeanNameAware,
        InitializingBean {
    
      private String name = "";
    
      private boolean allowNullValues = true;
    
      private KReadTransactionCache cache;
    
      /**
       * Specify the name of the cache.
       * <p>Default is "" (empty String).
       */
      public void setName(String name) {
        this.name = name;
      }
    
      /**
       * Set whether to allow {@code null} values
       * (adapting them to an internal null holder value).
       * <p>Default is "true".
       */
      public void setAllowNullValues(boolean allowNullValues) {
        this.allowNullValues = allowNullValues;
      }
    
      public void setBeanName(String beanName) {
        if (!StringUtils.hasLength(this.name)) {
          setName(beanName);
        }
      }
    
      public void afterPropertiesSet() {
        this.cache = new KReadTransactionCache(this.name, this.allowNullValues);
      }
    
      public KReadTransactionCache getObject() {
        return this.cache;
      }
    
      public Class<?> getObjectType() {
        return KReadTransactionCache.class;
      }
    
      public boolean isSingleton() {
        return false;
      }
    
    }
    

    然后,实现绑定到当前事务的反缓存

    import java.io.Serializable;
    import java.util.HashMap;
    import java.util.Map;
    
    import org.alfresco.repo.transaction.AlfrescoTransactionSupport;
    import org.alfresco.repo.transaction.AlfrescoTransactionSupport.TxnReadState;
    import org.springframework.cache.Cache;
    import org.springframework.cache.support.SimpleValueWrapper;
    
    public class KReadTransactionCache implements Cache {
    
      private static final Object NULL_HOLDER = new NullHolder();
    
      private final String name;
    
      private final boolean allowNullValues;
    
      /**
       * Create a new ConcurrentMapCache with the specified name.
       * @param name the name of the cache
       */
      public KReadTransactionCache(String name) {
        this(name, true);
      }
    
      protected static Map<Object, Object> getBindedCache(String name) {
        Map<Object, Object> cache = null;
        if (AlfrescoTransactionSupport.getTransactionReadState() == TxnReadState.TXN_READ_ONLY) {
          cache = AlfrescoTransactionSupport.getResource(name);
          if (cache == null) {
            cache = new HashMap<>();
          }
          AlfrescoTransactionSupport.bindResource(name, cache);
        }
        return cache;
      }
    
      /**
       * Create a new Map with the specified name and the
       * given internal ConcurrentMap to use.
       * @param name the name of the cache
       * @param allowNullValues whether to allow {@code null} values
       * (adapting them to an internal null holder value)
       */
      public KReadTransactionCache(String name, boolean allowNullValues) {
        this.name = name;
        this.allowNullValues = allowNullValues;
    
      }
    
      public String getName() {
        return this.name;
      }
    
      public Map getNativeCache() {
        return getBindedCache(name);
      }
    
      public boolean isAllowNullValues() {
        return this.allowNullValues;
      }
    
      public ValueWrapper get(Object key) {
        final Map<Object, Object> bindedCache = getBindedCache(name);
        if (bindedCache == null) {
          return null;
        }
        Object value = bindedCache.get(key);
        return (value != null ? new SimpleValueWrapper(fromStoreValue(value)) : null);
      }
    
      public void put(Object key, Object value) {
        final Map<Object, Object> bindedCache = getBindedCache(name);
        if (bindedCache == null) {
          return;
        }
    
        bindedCache.put(key, toStoreValue(value));
      }
    
      public void evict(Object key) {
        final Map<Object, Object> bindedCache = getBindedCache(name);
        if (bindedCache == null) {
          return;
        }
        bindedCache.remove(key);
      }
    
      public void clear() {
        final Map<Object, Object> bindedCache = getBindedCache(name);
        if (bindedCache == null) {
          return;
        }
        bindedCache.clear();
      }
    
      /**
       * Convert the given value from the internal store to a user value
       * returned from the get method (adapting {@code null}).
       * @param storeValue the store value
       * @return the value to return to the user
       */
      protected Object fromStoreValue(Object storeValue) {
        if (this.allowNullValues && storeValue == NULL_HOLDER) {
          return null;
        }
        return storeValue;
      }
    
      /**
       * Convert the given user value, as passed into the put method,
       * to a value in the internal store (adapting {@code null}).
       * @param userValue the given user value
       * @return the value to store
       */
      protected Object toStoreValue(Object userValue) {
        if (this.allowNullValues && userValue == null) {
          return NULL_HOLDER;
        }
        return userValue;
      }
    
      @SuppressWarnings("serial")
      private static class NullHolder implements Serializable {
      }
    
    }
    

    以及xml配置:

        <!-- *******************************
           ***** CACHE CONFIGURATION *****
           ******************************* -->
       <!-- simple cache manager -->
       <bean id="cacheManager" class="org.springframework.cache.support.SimpleCacheManager">
          <property name="caches">
             <set>
                <bean class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean" p:name="default" />
                <bean class="path.to.package.KReadTransactionCacheFactoryBean" p:name="cacheNameByAnnotation" />
                <!-- TODO Add other cache instances in here -->
             </set>
          </property>
       </bean>
    
        2
  •  0
  •   biiyamn    7 年前
    1. SimpleCacheManager对于测试编写为spring文档的环境非常有用
    2. SimpleCacheManager只支持静态模式,在这种模式下,缓存是在配置时预定义的,不允许在运行时添加缓存
    3. EhCache及其关联的spring-EhCacheManager桥可能是一个不错的选择