Skip to content

Improve Configuration Experience for Multiple CacheManagers #33282

@Crain-32

Description

@Crain-32

The automatic configuration of a cache is amazing for the simple cases, however quickly becomes weird if you decide to use multiple CacheManager instances.

For example you might want to have a Distributed Cache using Redis, and a Local Caffeine or ConcurrentMap Cache for small items, you'd need the following configuration.

@Configuration
@EnableCaching
public CachingConfig implements CachingConfigurer, ApplicationContextAware {
    private ApplicationContext ac;
    @Bean
    public CacheManager redisCacheManager(RedisConnectionFactory factory, CacheProperties props) {
      // Implementing Redis Cache
    }
    @Bean
    public CacheManager caffeineCache(CacheProperties cacheProperties) {
    // Implementing Caffeine Cache
    }
    
    @Override
    @Bean
    public CacheResolver cacheResolver() {
        var redisCache = ac.getBean("redisCacheManager", CacheManager.class);
        var caffeineCache = ac.getBean("caffeineCache", CacheManager.class);
        // Implement Resolver
    }
    @Override
    public KeyGenerator keyGenerator() {
        return new SimpleKeyGenerator();
    }
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.ac= applicationContext;
    }
}

From a user perspective there are some parts that are a little verbose compared to other configurations. Highlights would be bringing in the ApplicationContext, but the class really doesn't care for it, implementing the KeyGenerator using the same default Spring does (per CachingConfigurer Docs), and then not overriding CachingConfigurer::cacheManager() for a mixture of reasons.

I personally I think Caching could use a more "Default unless Declared" approach, where we could reduce this down to the following.

@Configuration
@EnableCaching
public CachingConfig  {
    @Bean
    public CacheManager redisCacheManager(RedisConnectionFactory factory, CacheProperties props) {
     // Implementing Redis Cache
    }

    @Bean
    public CacheManager caffeineCache(CacheProperties cacheProperties) {
    // Implementing Caffeine Cache
    }
    
    @Bean
    public CacheResolver cacheResolver(
        @Qualifier("redisCacheManager") CacheManager redis,
        @Qualifier("caffeineCache") CacheManager caffeine
        ) {
        // Implement Resolver
    }
}

This removes the KeyGenerator, swaps ApplicationContext::getBean with Parameter Injection, and removes the CachingConfigurer in favor of global bean detection. What other adjustments would the Spring Boot Team be open to?

Metadata

Metadata

Assignees

No one assigned

    Labels

    status: declinedA suggestion or change that we don't feel we should currently apply

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions