Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Custom CacheResolver not working

I have a Spring Boot project with a custom CacheResolver as I need to decide on runtime which cache I want to use, I don't have any compilation errors but, when I do some tests and place a break point at my custom CacheResolver it never steps into it.

This is my Configuration class for the Cache:

@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);
      } 
    }

Here is my 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;
  }
}

And here my DAO where I use the cache:

    @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
      }
.
.
.
}

I have tried implementing CacheResolver instead of extending AbstractCacheResolver but it didn't make any difference.

Thank you.

like image 354
tommylii Avatar asked Nov 01 '22 03:11

tommylii


1 Answers

Cache names need to be included at some point, just specifying the CacheResolver to use is not enough, the @Cacheable class needs to be aware of the available cache names, so I included them with the @CacheConfig annotation:

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

One thing that I don't like is that I need to provide a null CacheManager, even if I'm not using it, otherwise I get the following error:

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.

So I left it like this, and it works:

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

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

Reran my tests, stepping through my custom CacheResolver and it is behaving as expected resolving to the correct cache(s)

My configuration class is not extending CachingConfigurerSupport anymore.

like image 61
tommylii Avatar answered Nov 13 '22 16:11

tommylii