All Downloads are FREE. Search and download functionalities are using the official Maven repository.

cn.patterncat.cache.config.CascadeCacheConfig Maven / Gradle / Ivy

package cn.patterncat.cache.config;

import cn.patterncat.cache.component.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.actuate.autoconfigure.cache.CachesEndpointAutoConfiguration;
import org.springframework.boot.actuate.cache.CachesEndpoint;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration;
import org.springframework.boot.autoconfigure.cache.CacheManagerCustomizers;
import org.springframework.boot.autoconfigure.cache.CacheProperties;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurer;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.caffeine.CaffeineCacheManager;
import org.springframework.cache.interceptor.CacheErrorHandler;
import org.springframework.cache.interceptor.CacheResolver;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.PostConstruct;
import java.util.List;
import java.util.Map;

/**
 * http://localhost:8080/actuator/caches
 *
 * org/springframework/boot/actuate/cache/CachesEndpoint.java
 * org/springframework/boot/actuate/autoconfigure/cache/CachesEndpointAutoConfiguration.java
 * org/springframework/boot/actuate/cache/CachesEndpointWebExtension.java
 * org/springframework/cache/interceptor/AbstractCacheInvoker.java
 * org/springframework/cache/interceptor/CacheInterceptor.java
 * org/springframework/cache/jcache/interceptor/CachePutInterceptor.java
 * org/springframework/cache/jcache/interceptor/CacheRemoveEntryInterceptor.java
 * org/springframework/cache/jcache/interceptor/CacheResultInterceptor.java
 * org/springframework/boot/autoconfigure/cache/CacheConfigurations.java
 *
 * GenericCacheConfiguration 对应 SimpleCacheManager
 * SimpleCacheConfiguration 对应 ConcurrentMapCacheManager
 * RedisCacheConfiguration 对应 RedisCacheManager
 * CaffeineCacheConfiguration 对应 CaffeineCacheManager
 * NoOpCacheConfiguration 对应 NoOpCacheManager -- get出来的value为null,直接走原始方法
 *
 * Created by cat on 2019-03-12.
 */
@Configuration
@AutoConfigureAfter(CacheAutoConfiguration.class)
@AutoConfigureBefore(CachesEndpointAutoConfiguration.class)
@EnableCaching
public class CascadeCacheConfig implements CachingConfigurer {

    @Autowired(required = false)
    RedisCacheManager redisCacheManager;

    @Autowired
    CacheProperties cacheProperties;

    @Autowired
    CacheManagerCustomizers customizers;

    CascadeCacheManager cascadeCacheManager;

    CaffeineCacheManager caffeineCacheManager;

    @PostConstruct
    public void init(){
        //NOTE 这里试图想用caffeine来做redis的fallback,但是事以愿违,因为CompositeCacheManager的getCache是根据大的cache名称来的,redis manager有该名的cache,就始终返回redis manager了,不会使用caffeine
        CascadeCacheManager cacheManager = new CascadeCacheManager();
        this.caffeineCacheManager = createCaffeineCacheManager();
        if(redisCacheManager != null){
            cacheManager.setCacheManagers(List.of(redisCacheManager,caffeineCacheManager));
        }else{
            cacheManager.setCacheManagers(List.of(caffeineCacheManager));
        }

        //NoOpCacheManager其实只存key不存value,其cache为NoOpCache
        cacheManager.setFallbackToNoOpCache(false);

        this.cascadeCacheManager = cacheManager;
    }

    /**
     * 这里也不能托管,因为会导致CacheAutoConfiguration不能auto config
     * 因为都有@ConditionalOnMissingBean(CacheManager.class),所以没办法自动同时都有RedisCacheManager和CaffeineCacheManager
     * 这里选择让redis自动加载,手工配置caffeine,因为配置caffeine比较简单
     * org/springframework/boot/autoconfigure/cache/CaffeineCacheConfiguration.java
     * @return CaffeineCacheManager
     */
    public CaffeineCacheManager createCaffeineCacheManager(){
        CaffeineCacheManager cacheManager = new CaffeineCacheManager();
        String specification = cacheProperties.getCaffeine().getSpec();
        if (StringUtils.hasText(specification)) {
            cacheManager.setCacheSpecification(specification);
        }
        List cacheNames = cacheProperties.getCacheNames();
        if (!CollectionUtils.isEmpty(cacheNames)) {
            cacheManager.setCacheNames(cacheNames);
        }
        return customizers.customize(cacheManager);
    }

    /**
     * NOTE 这个bean托管给spring容器的话RedisCacheConfiguration就无法初始化redisCacheManager,因而这里去掉托管,改为手工调用InitializingBean接口的afterPropertiesSet方法
     * @return CacheManager
     */
    @Override
    public CacheManager cacheManager() {
        return cascadeCacheManager;
    }

    @Override
    public CacheResolver cacheResolver() {
        return new CascadeCacheResolver(cascadeCacheManager);
    }

    @Override
    public KeyGenerator keyGenerator() {
        return null;
    }

    @Override
    public CacheErrorHandler errorHandler() {
        return new LoggingCacheErrorHandler();
    }

    public RedisCacheManager getRedisCacheManager() {
        return redisCacheManager;
    }

    public CascadeCacheManager getCascadeCacheManager() {
        return cascadeCacheManager;
    }

    public CaffeineCacheManager getCaffeineCacheManager() {
        return caffeineCacheManager;
    }

    @Bean
    public CachesEndpoint cachesEndpoint() {
        //NOTE 由于cacheManager.getCache接口只返回一个,所以对于cascade的情况,这里还是分开返回cache manager ,不使用CascadeCacheManager或者CompositeCacheManager
        return new CachesEndpoint(Map.of("redisCacheManager",redisCacheManager,"caffeineCacheManager",caffeineCacheManager));
    }

    @Bean
    public CacheKeysEndpoint cacheKeysEndpoint(){
        return new CacheKeysEndpoint(Map.of("redisCacheManager",redisCacheManager,"caffeineCacheManager",caffeineCacheManager));
    }

    @Bean
    public CacheKeysEndpointWebExtension cacheKeysEndpointWebExtension(CacheKeysEndpoint cacheKeysEndpoint){
        return new CacheKeysEndpointWebExtension(cacheKeysEndpoint);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy