Cache缓存的用法

我爱海鲸 2025-01-20 10:20:51 暂无标签

简介Caffeine、redis缓存配置

Caffeine配置:

@Slf4j
@Configuration
@EnableCaching
public class CaffeineCacheConfig {

    private static final int MAX_REFRESH_COUNT = 2;

    private static Cache<Object, Integer> caffeine = Caffeine.newBuilder()
            .expireAfterAccess(Duration.ofMinutes(5))
            .build();

    @Bean
    public CacheLoader<Object, Object> cacheLoader() {
        return new CacheLoader<Object, Object>() {
            @Nullable
            @Override
            public Object load(@NonNull Object o) throws Exception {
                return null;
            }

            @Nullable
            @Override
            public Object reload(@NonNull Object key, @NonNull Object oldValue) throws Exception {
                Integer refreshCount = caffeine.get(key, k -> 0);
                if (refreshCount > MAX_REFRESH_COUNT) {
                    // 超过最大刷新次数时,强制重新加载
                    caffeine.invalidate(key);
                    return load(key);
                }
                caffeine.put(key, ++ refreshCount);
                return oldValue;
            }
        };
    }
}

pom依赖:

<dependency>
    <groupId>com.github.ben-manes.caffeine</groupId>
    <artifactId>caffeine</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cache</groupId>
    <artifactId>spring-cache</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-cache</artifactId>
</dependency>

使用的注解:

@Cacheable(value = "CACHE_DATA", key = "#id1+'-'+#id2", unless = "#result == null")
public Item getItemById(Long id) {
    // ...
}

只有在方法返回结果不为空的情况下才会缓存结果(unless 属性的作用)。并且,缓存的 key 是根据方法参数 id 来生成的。

在 Spring 配置类或主应用程序类上添加 @EnableCaching 注解,以开启缓存支持。

确保配置了合适的缓存管理器(如 EhCache, Caffeine, Redis 等)。

如果使用的是 XML 配置,确保 <cache:annotation-driven /> 元素已添加到你的配置文件中。

application.xml上配置:

---
spring:
  cache:
    type: caffeine
    caffeine:
      spec: initialCapacity=500,maximumSize=5000,expireAfterWrite=600s,refreshAfterWrite=500s
    cache-names: CACHE_DATA
  • type: CAFFEINE:指定了应用程序使用 Caffeine 作为默认的缓存提供者。

  • initialCapacity=500

    • 这是缓存初始化时分配的容量大小。当缓存创建时,它将预先分配一定的空间来存储缓存条目。这个值表示缓存开始时可以容纳的条目数量。
  • maximumSize=5000

    • 设置了缓存的最大容量。一旦缓存中的条目数超过了这个数值,最旧的条目将会被移除(根据 LRU 或其他策略)以腾出空间给新的条目。
  • expireAfterWrite=600s

    • 定义了写入后过期时间。这意味着从一个条目被添加或更新后的那一刻起,经过 600 秒(10 分钟)之后,该条目将被视为过期,并在下次访问时被移除。
  • refreshAfterWrite=500s

    • 指定刷新间隔时间。这表示如果一个条目在写入后超过 500 秒未被访问,则会在下一次访问时尝试刷新其内容。注意,refreshAfterWrite 并不会自动触发数据加载;它仅影响下一次访问时的行为。具体来说,只有当条目确实过期并且需要重新加载时才会发生刷新操作。

2025-01-20 start:

redis缓存配置

pom:

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-redis</artifactId>
		</dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-cache</artifactId>
        </dependency>

配置文件:RedisCacheConfig

import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.interceptor.CacheErrorHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.cache.RedisCacheWriter;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;

import java.time.Duration;

/**
 * spring-cache使用redis缓存配置
 */
@Slf4j
@Configuration
@EnableCaching
public class RedisCacheConfig extends CachingConfigurerSupport {

    @Bean
    public CacheManager cacheManager(RedisConnectionFactory connectionFactory) {
        RedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(connectionFactory);
        Jackson2JsonRedisSerializer<【返回的结果类】> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(【返回的结果类】);
        RedisCacheConfiguration configuration = RedisCacheConfiguration
                .defaultCacheConfig()
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer))
                 // 过期:一天
                .entryTtl(Duration.ofDays(1));
        return RedisCacheManager
                .builder(redisCacheWriter)
                .cacheDefaults(configuration)
                .build();
    }

    @Bean
    @Override
    public CacheErrorHandler errorHandler() {
        log.warn("Redis occur exception, use custom CacheErrorHandler to handle");
        return new CacheErrorHandler() {
            @Override
            public void handleCacheGetError(RuntimeException exception, Cache cache, Object key) {
                doHandleRedisErrorException(exception, key);
            }

            @Override
            public void handleCachePutError(RuntimeException exception, Cache cache, Object key, Object value) {
                doHandleRedisErrorException(exception, key);
            }

            @Override
            public void handleCacheEvictError(RuntimeException exception, Cache cache, Object key) {
                doHandleRedisErrorException(exception, key);
            }

            @Override
            public void handleCacheClearError(RuntimeException exception, Cache cache) {
                doHandleRedisErrorException(exception, null);
            }
        };
    }

    protected void doHandleRedisErrorException(RuntimeException exception, Object key) {
        log.warn("Redis occur exception:key=[{}]", key, exception);
        String redisKey = (String) key;
        if (redisKey.contains("LOCK")) {
            throw exception;
        }
    }
}

redis配置:RedisConfiguration

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

/**
 * redis配置
 * @author huangjuguan
 * @date 2020/7/8.
 */

@Configuration
public class RedisConfiguration {

    @Bean("objectRedisTemplate")
    public RedisTemplate<String, Object> objectRedisTemplate(RedisConnectionFactory factory) {

        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(factory);

        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(new StringRedisSerializer());

        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashValueSerializer(new Jackson2JsonRedisSerializer<>(Object.class));
        redisTemplate.setEnableTransactionSupport(true);
        return redisTemplate;
    }

}

使用同上

end

你好:我的2025