配置
TB支持两种缓存:Caffeine和Redis,通过配置cache.type来指定使用哪种缓存。
 
 位于 org.thingsboard.server.cache
Caffeine
配置类:CaffeineCacheConfiguration
@Configuration
@ConditionalOnProperty(prefix = "cache", value = "type", havingValue = "caffeine", matchIfMissing = true)
@ConfigurationProperties(prefix = "caffeine")
@EnableCaching
@Data
@Slf4j
public class CaffeineCacheConfiguration {
    // 具体缓存的配置
    private Map<String, CacheSpecs> specs;
    // 构造CacheManager对象,被其管理的缓存可以在Cacheable等注解中使用
    @Bean
    public CacheManager cacheManager() {
        log.trace("Initializing cache: {} specs {}", Arrays.toString(RemovalCause.values()), specs);
        SimpleCacheManager manager = new SimpleCacheManager();
        if (specs != null) {
            // 加载配置文件中定义的具体缓存配置
            List<CaffeineCache> caches = specs.entrySet().stream()
                    .map(entry -> buildCache(entry.getKey(), entry.getValue())).collect(Collectors.toList());
            manager.setCaches(caches);
        }
        //SimpleCacheManager is not a bean (will be wrapped), so call initializeCaches manually
        manager.initializeCaches();
        // 支持事务
        return new TransactionAwareCacheManagerProxy(manager);
    }
    // 构造一个缓存对象
    private CaffeineCache buildCache(String name, CacheSpecs cacheSpec) {
        final Caffeine<Object, Object> caffeineBuilder
                = Caffeine.newBuilder()
                 // 使用基于权重的回收策略:设置最大权重,当累计权重超过该值时,会触发驱逐
                 // 相比基于容量(key的数量)的回收策略,权重能考虑值的大小,
                 // 尤其是集合类型的值,可以更精确的控制缓存的大小
                .maximumWeight(cacheSpec.getMaxSize()) 
                // 设置值的权重计算方法
                .weigher(collectionSafeWeigher()) 
                // 设置基于时间的回收策略:在写入之后指定时间时删除
                .expireAfterWrite(cacheSpec.getTimeToLiveInMinutes(), TimeUnit.MINUTES)
                .ticker(ticker());
        return new CaffeineCache(name, caffeineBuilder.build());
    }
    
    @Bean
    public Ticker ticker() {
        return Ticker.systemTicker();
    }
    
    // 计算值的权重,如果值的类型是集合,则权重是集合的大小
    private Weigher<? super Object, ? super Object> collectionSafeWeigher() {
        return (Weigher<Object, Object>) (key, value) -> {
            if (value instanceof Collection) {
                return ((Collection) value).size();
            }
            return 1;
        };
    }    
}
配置类上的 @ConditionalOnProperty(prefix = “cache”, value = “type”, havingValue = “caffeine”, matchIfMissing = true)说明当配置使用caffeine缓存时,该配置类才生效.
回收策略
public static void main(String[] args) throws InterruptedException {
    Cache<Integer, Integer> cache = Caffeine.newBuilder()
            //设置最大权重为20
            .maximumWeight(20)
            //设置值的权重等于值
            .weigher((key, value) -> (int) value)
            .removalListener((Integer key, Object value, RemovalCause cause) ->
                    System.out.printf("Key %s was removed because (%s)%n", key, cause))
            .build();
    // 插入权重为19的键值对
    cache.put(0, 19);
    //打印缓存个数,结果为1
    System.out.println(cache.estimatedSize());
    // 插入权重为2的键值对,累计权重为21,会触发空间回收,基于TinyLRU算法驱逐key=0的键值对
    cache.put(1, 2);
    // 继续插入,累计权重为4,不会触发空间回收
    cache.put(2, 2);
    //稍微休眠一秒
    Thread.sleep(1000);
    //打印缓存个数,结果为2
    System.out.println(cache.estimatedSize());
}
// 控制台打印:
//1
//Key 0 was removed because (SIZE) key 0 被驱逐因为缓存大小限制
//2
支持事务
假设方法updateUser被@CachePut修饰,则更新User后更新缓存
 在一个事务方法中先调用updateUser方法,然后调用addUpdateLog方法;
 在实际执行时,执行addUpdateLog方法发生异常,导致事务回滚;
 如果缓存不支持事务,则会导致缓存脏数据的问题,流程如下:
 
Redis
配置类:TBRedisCacheConfiguration
// 连接池
@Bean
public RedisConnectionFactory redisConnectionFactory() {
    return loadFactory();
}
// 支持Redis多种部署模式,因此由子类定义
protected abstract JedisConnectionFactory loadFactory();
/**
 * 传入连接工厂Bean定义RedisCacheManager,支持事务
 * Transaction aware RedisCacheManager.
 * Enable RedisCaches to synchronize cache put/evict operations with ongoing Spring-managed transactions.
 */
@Bean
public CacheManager cacheManager(RedisConnectionFactory cf) {
    DefaultFormattingConversionService redisConversionService = new DefaultFormattingConversionService();
    RedisCacheConfiguration.registerDefaultConverters(redisConversionService);
    registerDefaultConverters(redisConversionService);
    RedisCacheConfiguration configuration = RedisCacheConfiguration.defaultCacheConfig().withConversionService(redisConversionService);
    return RedisCacheManager.builder(cf)
            .cacheDefaults(configuration)
            .transactionAware()
            .build();
}
@Bean
public RedisTemplate<String, Object> redisTemplate() {
    RedisTemplate<String, Object> template = new RedisTemplate<>();
    template.setConnectionFactory(redisConnectionFactory());
    return template;
}
支持Redis的两种模式:Standalone和Cluster;因此构造连接方法在两个子类中定义:
 
使用
因为使用了CacheManager因此可以直接使用注解来使用缓存
 cacheNmaes指的是使用哪个缓存,当使用Caffeine缓存时会根据配置文件加载多个缓存Bean:








![[附源码]java毕业设计医院就诊流程管理系统](https://img-blog.csdnimg.cn/7064e12862744af0a499f555bacbf485.png)









