Using multiple cache implementations with Spring C

2020-05-28 11:33发布

问题:

I'm working on a Spring Boot app where I need to use both distributed (e.g. Hazelcast) and local (e.g. Guava) caches. Is there a way to configure Spring Cache to use both when using @Cacheable and decide which implementation is needed based on the cache name?

I tried with creating a configuration for both HZ and Guava defining the cache names inside, but Spring complains that it couldn't find the cache name that is supposed to handled by HZ. When I use exclusively HZ or Guava they work.

回答1:

Which implementation is needed based on the cache name?

Not based on the cache name but yes based on CacheManager its possible, declare one of them as Primary CacheManager, as follows:

@Configuration
@EnableCaching
@PropertySource(value = { "classpath:/cache.properties" })
public class CacheConfig {

    @Bean
    @Primary
    public CacheManager hazelcastCacheManager() {
        ClientConfig config = new ClientConfig();
        HazelcastInstance client = HazelcastClient.newHazelcastClient(config);
        return new HazelcastCacheManager(client);
    }

    @Bean
    public CacheManager guavaCacheManager() {
         GuavaCacheManager cacheManager = new GuavaCacheManager("mycache");
           CacheBuilder<Object, Object> cacheBuilder = CacheBuilder.newBuilder()
           .maximumSize(100)
           .expireAfterWrite(10, TimeUnit.MINUTES);
           cacheManager.setCacheBuilder(cacheBuilder);
           return cacheManager;
    }

}

And specify it at class level as:

@Service
@CacheConfig(cacheManager="hazelcastCacheManager")
public class EmployeeServiceImpl implements IEmployeeService {

}

Or at method level as:

@Service
public class EmployeeServiceImpl implements IEmployeeService {

    @Override
    @Cacheable(value = "EMPLOYEE_", key = "#id", cacheManager= "guavaCacheManager")
    public Employee getEmployee(int id) {
        return new Employee(id, "A");
    }

}

If you have to stick on Cache name only then you can multiple CacheManager.



回答2:

You have 2 options.

One is as @Arpit mentioned: Define multiple CacheManagers and specify it in either method-level annotations (@Cacheable, @CachePut, etc) or class-level annotations (@CacheConfig)

You can also create custom annotations:

@CacheConfig(cacheManager = "guavaCacheManager")
@Target(value = ElementType.TYPE)
@Retention(value = RetentionPolicy.RUNTIME)
public @interface GuavaCacheable {
}

@GuavaCacheable
@Service
public class MyServiceImpl implements MyService {
}

And as the second option, you can create a custom cache resolver if your caching needs are complex.

You can look here for a custom CacheResolver that manages multiple CacheManagers and supports enabling/disabling. But for most cases, CacheResolver is overkill.