5

我有一个带有自定义的 Spring Boot 项目,CacheResolver因为我需要决定运行时要使用哪个缓存,我没有任何编译错误,但是,当我进行一些测试并在我的自定义设置断点时,CacheResolver它永远不会进入它。

这是我的缓存配置类:

@Configuration
@EnableCaching(proxyTargetClass = true)
@PropertySource(CacheConfig.CLASSPATH_DEPLOY_CACHE_PROPERTIES_PROPERTIES)
public class CacheConfig extends CachingConfigurerSupport{

      public static final String CLASSPATH_DEPLOY_CACHE_PROPERTIES_PROPERTIES = "classpath:/deploy/cache-properties.properties";

      public static final String CACHEABLE_DOCUMENTS_PROPERTY = "cacheable.documents";
      public static final String TTL_CACHEABLE_DOCUMENTS_PROPERTY = "ttl.cacheable.documents";
      public static final String SIZED_CACHEABLE_DOCUMENTS_PROPERTY = "sized.cacheable.documents";
      public static final String CACHE_NAME = "permanentCache";
      public static final String TTL_CACHE = "ttlCache";
      public static final String SIZED_CACHE = "sizedCache";
      public static final String CACHEABLE_DOCUMENTS = "cacheableDocuments";
      public static final String SIZED_CACHEABLE_DOCUMENTS = "sizedCacheableDocuments";
      public static final int WEIGHT = 1000000;
      public static final int TO_KBYTES = 1000;

      @Inject
      protected Environment environment;

      //@Bean
      @Override
      public CacheManager cacheManager() {
        SimpleCacheManager cacheManager = new SimpleCacheManager();
        GuavaCache sizedCache = new GuavaCache(SIZED_CACHE, CacheBuilder.newBuilder().maximumWeight(WEIGHT).weigher(
                (key, storable) -> {
                  String json = ((Storable) storable).toJson();
                  return json.getBytes().length / TO_KBYTES;
                }
        ).build());
        GuavaCache permanentCache = new GuavaCache(CACHE_NAME,CacheBuilder.newBuilder().build());
        //GuavaCache ttlCache = new GuavaCache(TTL_CACHE, CacheBuilder.newBuilder().expireAfterWrite(30, TimeUnit.MINUTES).build());
        cacheManager.setCaches(Arrays.asList(permanentCache,sizedCache));
        return cacheManager;
      }

      @Bean(name = "wgstCacheResolver")
      @Override
      public CacheResolver cacheResolver(){
        CacheResolver cacheResolver = new WgstCacheResolver(cacheManager(),cacheableDocuments(),sizedCacheableDocuments());
        return cacheResolver;
      }


      @Bean(name = CACHEABLE_DOCUMENTS)
      public List<String> cacheableDocuments(){
        String[] cacheableDocuments = StringUtils.commaDelimitedListToStringArray(environment.getProperty(CACHEABLE_DOCUMENTS_PROPERTY));
        return Arrays.asList(cacheableDocuments);
      }

      @Bean(name = SIZED_CACHEABLE_DOCUMENTS)
      public List<String> sizedCacheableDocuments(){
        String[] sizedCacheableDocuments = StringUtils.commaDelimitedListToStringArray(environment.getProperty(SIZED_CACHEABLE_DOCUMENTS_PROPERTY));
        return Arrays.asList(sizedCacheableDocuments);
      } 
    }

这是我的 CacheResolver

public class WgstCacheResolver extends AbstractCacheResolver {

  private final List<String> cacheableDocuments;
  private final List<String> sizedCacheableDocuments;

  public WgstCacheResolver(final CacheManager cacheManager,final List<String> cacheableDocuments, final List<String> sizedCacheableDocuments) {
    super(cacheManager);
    this.cacheableDocuments = cacheableDocuments;
    this.sizedCacheableDocuments = sizedCacheableDocuments;
  }

  /**
   * Resolves the cache(s) to be updated on runtime
   * @param context
   * @return*/
  @Override
  protected Collection<String> getCacheNames(final CacheOperationInvocationContext<?> context) {

    final Collection<String> cacheNames = new ArrayList<>();
    final AbstractDao dao = (AbstractDao)context.getTarget();
    final String documentType = dao.getDocumentType().toString();
    if (cacheableDocuments.contains(documentType)){
      cacheNames.add("permanentCache");
    }
    if (sizedCacheableDocuments.contains(documentType)){
      cacheNames.add("sizedCache");
    }
    return cacheNames;
  }
}

这里是我使用缓存的 DAO:

    @Component
    @Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE, proxyMode = ScopedProxyMode.DEFAULT)
    @CacheConfig(cacheResolver = "wgstCacheResolver")
    public class CacheableDao<T extends Storable> extends AbstractDao<T> {

      private final Logger logger = LoggerFactory.getLogger(CacheableDao.class);

      public CacheableDao(final Bucket bucket, final Class<T> typeParameterClass, final DocumentType documentType) {
        super(bucket, typeParameterClass, documentType);
      }

      @Cacheable(key = "{#root.methodName, #root.target.generateFullKey(#key)}")
      public T get(final String key) throws DatastoreAccessException, ObjectMappingException {
        //do something
      }
.
.
.
}

我尝试过实施CacheResolver而不是扩展,AbstractCacheResolver但没有任何区别。

谢谢你。

4

2 回答 2

2

在某些时候需要包含缓存名称,仅指定CacheResolver要使用是不够的,@Cacheable该类需要知道可用的缓存名称,因此我将它们包含在@CacheConfig注释中:

@CacheConfig(cacheNames = {WgstCacheConfig.PERMANENT_CACHE, WgstCacheConfig.SIZED_CACHE},
    cacheResolver = WgstCacheConfig.WGST_CACHE_RESOLVER)
public class CacheableDao<T extends Storable> extends AbstractDao<T> {

我不喜欢的一件事是我需要提供一个 null CacheManager,即使我没有使用它,否则我会收到以下错误:

Caused by: java.lang.IllegalStateException: No CacheResolver specified, and no bean of type CacheManager found. Register a CacheManager bean or remove the @EnableCaching annotation from your configuration.

所以我就这样离开了它,它可以工作:

  @Bean
  public CacheManager cacheManager() {
    return null;
  }

  @Bean(name = WGST_CACHE_RESOLVER)
  public CacheResolver cacheResolver(){
    CacheResolver cacheResolver = new WgstCacheResolver(cacheableDocuments(),sizedCacheableDocuments(),getPermanentCache(),
                                                        getSizedCache());
    return cacheResolver;
  }

重新运行我的测试,逐步完成我的自定义CacheResolver,它的行为与预期的一样,解析为正确的缓存

我的配置类不再扩展CachingConfigurerSupport

于 2015-05-27T12:38:33.773 回答
0

经过一番来回(对不起!)事实证明这确实是 Spring Framework 中的一个错误。

我创建了SPR-13081。期待下一个维护版本 ( 4.1.7.RELEASE) 的修复。感谢您的示例项目!

于 2015-05-29T08:21:32.780 回答