Spring Boot 集成 Redis 缓存并使用 FastJSON2 作为序列化器的完整配置指南
在现代 Web 应用中,缓存是提升系统性能和减少数据库压力的重要手段。在最基本的SSM开发过程中,Springboot可以方便的将缓存和Redis集成,可以十分便捷的用注解开发。
个人情怀让我使用fastjson。升级到fastjson2后,原本的autotype被废除,不管是官方给出的代码示例还是论坛社区,都没有对泛型数据的支持,对于特定需求使用起来很不方便。
泛型:如果你有一个普通 Java Bean (FileEntity) ,那么List, Map<String, Object> 等就是泛型集合
1 引入依赖
pom.xml 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <dependency> <groupId>com.alibaba.fastjson2</groupId> <artifactId>fastjson2</artifactId> <version>2.0.57</version> </dependency> <dependency> <groupId>com.alibaba.fastjson2</groupId> <artifactId>fastjson2-extension-spring6</artifactId> <version>2.0.57</version> </dependency> </dependencies>
2 创建自定义序列器
FastJsonRedisSerializer.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 package com.example.demo.config; import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSONReader; import com.alibaba.fastjson2.TypeReference; import org.springframework.data.redis.serializer.RedisSerializer; import org.springframework.data.redis.serializer.SerializationException; import java.lang.reflect.Type; public class FastJsonRedisSerializer<T> implements RedisSerializer<T> { private static final JSONReader.Filter AUTO_TYPE_FILTER = JSONReader.autoTypeFilter( "com.example.demo.entity.", // 替换为你的实体包名 "java.util.ArrayList", "java.util.HashMap" ); private final Type type; public FastJsonRedisSerializer(Type type) { this.type = type; } public FastJsonRedisSerializer(Class<T> clazz) { this.type = clazz; } @Override public byte[] serialize(T t) throws SerializationException { if (t == null) return new byte[0]; return JSON.toJSONBytes(t, JSON.Feature.WriteClassName); } @Override public T deserialize(byte[] bytes) throws SerializationException { if (bytes == null || bytes.length == 0) return null; return JSON.parseObject(bytes, type, AUTO_TYPE_FILTER, JSON.Feature.SupportAutoType); } }
FastJson2StringRedisSerializer.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 package com.example.demo.config; import org.springframework.data.redis.serializer.RedisSerializer; import org.springframework.data.redis.serializer.SerializationException; import java.nio.charset.StandardCharsets; public class FastJson2StringRedisSerializer implements RedisSerializer<String> { @Override public byte[] serialize(String s) throws SerializationException { return s == null ? new byte[0] : s.getBytes(StandardCharsets.UTF_8); } @Override public String deserialize(byte[] bytes) throws SerializationException { return bytes == null || bytes.length == 0 ? null : new String(bytes, StandardCharsets.UTF_8); } }
3 配置Config
RedisConfig.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 package com.example.demo.config; 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.RedisTemplate; import org.springframework.data.redis.serializer.StringRedisSerializer; @Configuration public class RedisConfig { @Bean public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory factory) { RedisTemplate<Object, Object> template = new RedisTemplate<>(); template.setConnectionFactory(factory); FastJsonRedisSerializer<Object> valueSerializer = new FastJsonRedisSerializer<>(Object.class); FastJson2StringRedisSerializer stringSerializer = new FastJson2StringRedisSerializer(); template.setKeySerializer(stringSerializer); // key: String template.setHashKeySerializer(stringSerializer); // hashKey: String template.setValueSerializer(valueSerializer); // value: 泛型对象 template.setHashValueSerializer(valueSerializer); // hashValue: 泛型对象 template.setDefaultSerializer(valueSerializer); template.setStringSerializer(stringSerializer); template.afterPropertiesSet(); return template; } }
配置 RedisCacheManager(用于 @Cacheable 等注解)
RedisCacheConfig.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 package com.example.demo.config; import org.springframework.cache.annotation.EnableCaching; 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.connection.RedisConnectionFactory; import org.springframework.data.redis.serializer.RedisSerializationContext; import java.time.Duration; @Configuration @EnableCaching public class RedisCacheConfig { @Bean public RedisCacheManager redisCacheManager(RedisConnectionFactory factory) { FastJsonRedisSerializer<Object> serializer = new FastJsonRedisSerializer<>(Object.class); RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig() .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(serializer)) .entryTtl(Duration.ofMinutes(30)); // 设置缓存过期时间 return RedisCacheManager.builder(factory) .cacheDefaults(config) .build(); } }
到此配置全部完毕
4 Spring Cache 注解详解与使用示例 4.1 @Cacheable 用途 :标记方法返回值需被缓存。若缓存存在,则直接返回;否则执行方法体并缓存结果。
1 2 @Cacheable(value = "fileCache", key = "#id") FileEntity getFileById (UUID id) ;
4.2 @CachePut 用途 :更新缓存,总是执行方法并将结果写入缓存。
1 2 @CachePut(value = "fileCache", key = "#result.id") FileEntity saveFile (FileEntity file) ;
4.3 @CacheEvict 用途 :清除缓存中的条目。
1 2 @CacheEvict(value = "fileCache", key = "#id") void deleteFile (UUID id) ;
清空整个缓存区域:
1 2 @CacheEvict(value = "fileListCache", allEntries = true) void clearAllFiles () ;
4.4 @CacheConfig 用途 :类级别共享缓存配置
1 2 3 4 5 6 7 @CacheConfig(cacheNames = "fileCache") public class FileService { @Cacheable(key = "#id") public FileEntity getFileById (UUID id) { return fileMapper.selectById(id); } }
4.5 业务层使用示例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 @Service public class FileService { @Autowired private FileRepository fileRepository; @Cacheable(value = "fileCache", key = "#id") public FileEntity getFileById (UUID id) { return fileRepository.selectById(id); } @CachePut(value = "fileCache", key = "#result.id") public FileEntity saveFile (FileEntity file) { fileRepository.insert(file); return file; } @CacheEvict(value = "fileCache", key = "#id") public void deleteFile (UUID id) { fileRepository.deleteById(id); } @Cacheable(value = "fileListCache", key = "'all'") public List<FileEntity> getAllFiles () { return fileRepository.selectAll(); } }