Tùng Trần
Tùng Trần

Reputation: 11

Meet not eligible for auto-proxying when try to add cache interceptor

https://www.baeldung.com/spring-two-level-cache error I am implementing two levels of cache according to this article, however when I add the cache inteceptor bean it will give the above warning.

import com.foodey.server.interceptor.TwoLevelCacheInterceptor;
import com.github.benmanes.caffeine.cache.CaffeineSpec;
import com.github.benmanes.caffeine.jcache.CacheManagerImpl;
import com.github.benmanes.caffeine.jcache.configuration.CaffeineConfiguration;
import com.github.benmanes.caffeine.jcache.spi.CaffeineCachingProvider;
import java.net.URI;
import java.time.Duration;
import java.util.OptionalLong;
import java.util.Properties;
import java.util.concurrent.TimeUnit;
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
import org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.AnnotationCacheOperationSource;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.caffeine.CaffeineCacheManager;
import org.springframework.cache.interceptor.CacheInterceptor;
import org.springframework.cache.interceptor.CacheOperationSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;

@Configuration
@EnableCaching
@ImportAutoConfiguration({
  CacheAutoConfiguration.class,
})
public class CacheConfig {

  // https://stackoverflow.com/questions/77973235/why-is-bucket4j-not-working-with-caffeine
  // Implementing a cache manager for bucket4j
  @Bean
  @Lazy
  public javax.cache.CacheManager cacheManagerForBucket() {
    CacheManagerImpl impl =
        new CacheManagerImpl(
            new CaffeineCachingProvider(),
            false,
            URI.create("com.github.benmanes.caffeine.jcache.spi.CaffeineCachingProvider"),
            Thread.currentThread().getContextClassLoader(),
            new Properties());
    CaffeineConfiguration<Object, Object> configuration =
        new CaffeineConfiguration<Object, Object>();
    configuration.setExpireAfterAccess(
        OptionalLong.of(TimeUnit.NANOSECONDS.convert(259200, TimeUnit.SECONDS)));
    impl.createCache(
        "rate-limit-filter", configuration); // the cache for dynamic rate limit configiration
    impl.createCache("rate-limit-buckets", configuration); // the cache for bucket4j
    return impl;
  }

  // @Bean
  // @Primary
  // public CacheManager caffeineCacheManager(CaffeineCache caffeineCache) {
  //   SimpleCacheManager manager = new SimpleCacheManager();
  //   manager.setCaches(Arrays.asList(caffeineCache));
  //   return manager;
  // }

  @Primary
  @Bean("caffeineCacheManager")
  public CacheManager caffeineCacheManager() {
    // SimpleCacheManager cacheManager = new SimpleCacheManager();
    CaffeineCacheManager cacheManager =
        new CaffeineCacheManager("product", "products", "shop", "shops");

    cacheManager.setCaffeineSpec(CaffeineSpec.parse("maximumSize=3000,expireAfterAccess=30000s"));
    return cacheManager;
  }

  // @Bean
  // public CaffeineCache caffeineCacheConfig() {
  //   return new CaffeineCache(
  //       "product",
  //       Caffeine.newBuilder()
  //           .expireAfterWrite(Duration.ofSeconds(3))
  //           .initialCapacity(1)
  //           .maximumSize(2000)
  //           .build());
  // }

  // @Bean
  // public CacheManager caffeineCacheManager(CaffeineCache caffeineCache) {
  //   SimpleCacheManager manager = new SimpleCacheManager();
  //   manager.setCaches(Arrays.asList(caffeineCache));
  //   return manager;
  // }

  // @Bean
  //    public CaffeineCache caffeineCacheConfig() {
  //        return new CaffeineCache("customerCache", Caffeine.newBuilder()
  //          .expireAfterWrite(Duration.ofMinutes(1))
  //          .initialCapacity(1)
  //          .maximumSize(2000)
  //          .build());
  //    }

  @Bean
  public RedisCacheConfiguration redisCacheConfiguration() {
    return RedisCacheConfiguration.defaultCacheConfig()
        .entryTtl(Duration.ofMinutes(5))
        .disableCachingNullValues()
        .serializeValuesWith(
            RedisSerializationContext.SerializationPair.fromSerializer(
                new GenericJackson2JsonRedisSerializer()));
  }

  @Bean("redisCacheManager")
  public CacheManager redisCacheManager(
      RedisConnectionFactory connectionFactory, RedisCacheConfiguration cacheConfiguration) {
    return RedisCacheManager.RedisCacheManagerBuilder.fromConnectionFactory(connectionFactory)
        .withCacheConfiguration("product", cacheConfiguration)
        .build();
  }

  @Bean
  public CacheInterceptor cacheInterceptor(
      CacheManager caffeineCacheManager, CacheOperationSource cacheOperationSource) {
    CacheInterceptor interceptor = new TwoLevelCacheInterceptor(caffeineCacheManager);
    interceptor.setCacheOperationSources(cacheOperationSource);
    return interceptor;
  }

  @Bean
  public CacheOperationSource cacheOperationSource() {
    return new AnnotationCacheOperationSource();
  }
}
package com.foodey.server.interceptor;

import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.cache.interceptor.CacheInterceptor;
import org.springframework.data.redis.cache.RedisCache;

public class TwoLevelCacheInterceptor extends CacheInterceptor {

  private final CacheManager caffeineCacheManager;

  public TwoLevelCacheInterceptor(CacheManager caffeineCacheManager) {
    this.caffeineCacheManager = caffeineCacheManager;
  }

  @Override
  protected Cache.ValueWrapper doGet(Cache cache, Object key) {
    Cache.ValueWrapper existingCacheValue = super.doGet(cache, key);

    if (existingCacheValue != null && cache.getClass() == RedisCache.class) {
      Cache caffeineCache = caffeineCacheManager.getCache(cache.getName());
      if (caffeineCache != null) {
        caffeineCache.putIfAbsent(key, existingCacheValue.get());
      }
    }

    return existingCacheValue;
  }
}
package com.foodey.server.config;

import lombok.RequiredArgsConstructor;
import org.redisson.api.RedissonClient;
import org.redisson.spring.data.connection.RedissonConnectionFactory;
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisKeyValueAdapter;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.repository.configuration.EnableRedisRepositories;

@Configuration
@RequiredArgsConstructor
@EnableRedisRepositories(
    enableKeyspaceEvents = RedisKeyValueAdapter.EnableKeyspaceEvents.ON_STARTUP)
@ImportAutoConfiguration({
  RedisAutoConfiguration.class,
})
public class RedisConfig {

  // @Value("${spring.data.redis.host}")
  // private String HOST;

  // @Value("${spring.data.redis.port}")
  // private String PORT;

  // @Value("${spring.data.redis.password}")
  // private String PASSWORD;

  @Bean
  public RedisConnectionFactory redissonConnectionFactory(RedissonClient redisson) {
    return new RedissonConnectionFactory(redisson);
  }

  @Bean
  @Primary
  public RedisTemplate<Object, Object> redisTemplate(
      RedisConnectionFactory redissonConnectionFactory) {
    RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
    redisTemplate.setConnectionFactory(redissonConnectionFactory);
    return redisTemplate;
  }

  // @Bean
  // public Config config() {
  //   Config config = new Config();
  //   String address = String.format("redis://%s:%s", HOST, PORT);

  //   config.useSingleServer().setAddress(address).setPassword(PASSWORD);
  //   return config;
  // }
}

I tried adding lazy to the beans but it doesn't seem to work how to handle it?

  @Bean
  @Lazy
  public CacheInterceptor cacheInterceptor(
      CacheManager caffeineCacheManager, CacheOperationSource cacheOperationSource) {
    CacheInterceptor interceptor = new TwoLevelCacheInterceptor(caffeineCacheManager);
    interceptor.setCacheOperationSources(cacheOperationSource);
    return interceptor;
  }

  @Bean
  @Lazy
  public CacheOperationSource cacheOperationSource() {
    return new AnnotationCacheOperationSource();
  }

I also try to create another config class for two inteceptor beans but still not work.

package com.foodey.server.config;

import com.foodey.server.interceptor.TwoLevelCacheInterceptor;

import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.AnnotationCacheOperationSource;
import org.springframework.cache.interceptor.CacheInterceptor;
import org.springframework.cache.interceptor.CacheOperationSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;

@Configuration
public class CacheInterceptorConfig {

  @Bean
  @Lazy
  public CacheOperationSource cacheOperationSource() {
    return new AnnotationCacheOperationSource();
  }

  @Bean
  @Lazy
  public CacheInterceptor cacheInterceptor(
      CacheManager caffeineCacheManager, CacheOperationSource cacheOperationSource) {
    CacheInterceptor interceptor = new TwoLevelCacheInterceptor(caffeineCacheManager);
    interceptor.setCacheOperationSources(cacheOperationSource);
    return interceptor;
  }
}
 

Upvotes: 0

Views: 41

Answers (0)

Related Questions