From a9f95e2bc9f3c5cbb2b182b2ac647abf9211830f Mon Sep 17 00:00:00 2001 From: pbvfus8to <480171784@qq.com> Date: Wed, 18 Dec 2024 11:14:29 +0800 Subject: [PATCH] Update RedisCacheConfig.java --- .../shop/common/config/RedisCacheConfig.java | 178 +++++++++++++++--- 1 file changed, 151 insertions(+), 27 deletions(-) diff --git a/yami-shop-common/src/main/java/com/yami/shop/common/config/RedisCacheConfig.java b/yami-shop-common/src/main/java/com/yami/shop/common/config/RedisCacheConfig.java index 0d90d6b..f012257 100644 --- a/yami-shop-common/src/main/java/com/yami/shop/common/config/RedisCacheConfig.java +++ b/yami-shop-common/src/main/java/com/yami/shop/common/config/RedisCacheConfig.java @@ -8,50 +8,174 @@ * 版权所有,侵权必究! */ +// 该类所属的包名,表明其位于商城项目的通用(common)配置(config)包下,主要用于对Redis缓存相关的配置进行定义和设置,通过Spring的配置类机制, +// 在满足一定条件(配置文件中spring.cache.type = redis时)生效,来实现Redis缓存在项目中的集成与定制化配置。 package com.yami.shop.common.config; -import com.yami.shop.common.bean.AliDaYu; -import com.yami.shop.common.bean.ImgUpload; -import com.yami.shop.common.bean.Qiniu; -import lombok.Data; -import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.context.annotation.PropertySource; -import org.springframework.stereotype.Component; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.MapperFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.databind.json.JsonMapper; +import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import org.springframework.cache.CacheManager; +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.cache.RedisCacheWriter; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer; +import org.springframework.data.redis.serializer.RedisSerializationContext; +import org.springframework.data.redis.serializer.RedisSerializer; +import org.springframework.data.redis.serializer.StringRedisSerializer; + +import java.time.Duration; +import java.util.HashMap; +import java.util.Map; /** - * 该类作为商城配置文件相关的实体类,用于绑定配置文件中的各项配置信息到对应的属性上,方便在整个项目中获取和使用商城相关的配置参数, - * 通过使用 Spring 的相关注解(@Component、@ConfigurationProperties、@PropertySource),可以将配置文件中的配置值自动注入到这些属性中, - * 使得项目中的不同模块能够方便地获取如七牛云配置、阿里大鱼短信平台配置、加解密 token 的密钥以及本地文件上传配置等信息,实现配置的统一管理和灵活使用。 + * RedisCacheConfig类是一个Spring的配置类,用于配置Redis缓存相关的各种组件和行为,使得项目能够基于Redis实现高效的缓存功能,并且可以根据实际需求进行灵活的定制化配置。 + * 只有当项目的配置文件中指定spring.cache.type = redis时,这里定义的Redis缓存相关配置才会生效,用于控制缓存的存储、序列化、过期时间等关键特性。 * * @author lgh */ -@Data -@Component -@PropertySource("classpath:shop.properties") -@ConfigurationProperties(prefix = "shop") -public class ShopBasicConfig { +@EnableCaching +// 使用@EnableCaching注解开启Spring的缓存功能,使得在项目中可以使用诸如@Cacheable、@CachePut、@CacheEvict等缓存相关的注解来方便地操作缓存,提高应用性能。 +@Configuration +// 使用@Configuration注解表明该类是一个配置类,Spring会扫描这个类,并根据其中定义的@Bean方法来创建相应的Bean实例,注入到Spring容器中供其他组件使用。 +public class RedisCacheConfig { + + /** + * 创建并配置CacheManager的Bean方法,CacheManager是Spring缓存抽象的核心接口,用于管理缓存,在这里具体配置了基于Redis的缓存管理方式。 + * 通过传入RedisConnectionFactory(用于创建与Redis服务器的连接)和RedisSerializer(用于对缓存数据进行序列化和反序列化操作), + * 构建了一个RedisCacheManager实例,该实例负责管理Redis缓存的各种配置和行为,如缓存的默认过期时间、特定缓存键的过期时间配置等。 + * + * @param redisConnectionFactory 用于创建与Redis服务器连接的工厂类实例,通过它可以获取到与Redis服务器通信的连接对象,是操作Redis缓存的基础依赖。 + * @param redisSerializer 用于对缓存中存储的对象进行序列化和反序列化的序列化器,确保对象能够正确地在Java内存和Redis存储之间进行转换,保证数据的一致性和可存储性。 + * @return 返回配置好的RedisCacheManager实例,用于管理项目中的Redis缓存,将其注入到Spring容器中,以便其他组件可以获取并使用该缓存管理器来操作缓存。 + */ + @Bean + public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory, RedisSerializer redisSerializer) { + + RedisCacheManager redisCacheManager = new RedisCacheManager( + RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory), + // 默认策略,未配置的 key 会使用这个 + this.getRedisCacheConfigurationWithTtl(3600, redisSerializer), + // 指定 key 策略 + this.getRedisCacheConfigurationMap(redisSerializer) + ); + redisCacheManager.setTransactionAware(true); + return redisCacheManager; + } + + /** + * 用于获取特定缓存键对应的Redis缓存配置映射(Map)的私有方法,通过创建一个HashMap实例,并向其中添加特定缓存键(这里是"product")与对应的Redis缓存配置信息, + * 使得可以针对不同的缓存键设置不同的缓存过期时间等配置,方便根据业务需求对不同类型的数据缓存进行精细化管理。 + * + * @param redisSerializer 用于对缓存数据进行序列化和反序列化操作的序列化器,确保缓存配置中涉及的数据能够正确地进行序列化处理,与整体的缓存数据格式保持一致。 + * @return 返回包含特定缓存键与对应Redis缓存配置信息的Map,用于在创建RedisCacheManager时设置指定键的缓存策略,以便根据不同的缓存键应用不同的缓存过期时间等规则。 + */ + private Map getRedisCacheConfigurationMap(RedisSerializer redisSerializer) { + Map redisCacheConfigurationMap = new HashMap<>(16); + redisCacheConfigurationMap.put("product", this.getRedisCacheConfigurationWithTtl(1800, redisSerializer)); + return redisCacheConfigurationMap; + } /** - * 用于存储七牛云的配置信息的属性,七牛云可能用于文件存储、图片上传等功能,其配置信息包含诸如访问密钥、存储区域等内容, - * 通过此属性可以在项目中方便地获取七牛云相关配置,以便与七牛云服务进行集成,实现文件上传、管理等操作。 + * 用于获取带有指定过期时间(TTL,Time To Live)的Redis缓存配置的私有方法,通过以默认的Redis缓存配置(RedisCacheConfiguration.defaultCacheConfig())为基础, + * 使用传入的序列化器(redisSerializer)来配置缓存值的序列化方式,并设置缓存条目的过期时间(通过Duration.ofSeconds(seconds)指定秒数),从而生成符合特定需求的Redis缓存配置信息。 + * + * @param seconds 缓存条目的过期时间,以秒为单位,用于控制缓存数据在Redis中存储的有效时长,超过这个时间后,缓存数据将被自动清除,以保证缓存数据的时效性和内存空间的合理利用。 + * @param redisSerializer 用于对缓存中存储的对象进行序列化和反序列化的序列化器,确保缓存数据能够按照指定的格式进行转换,以便正确地存储在Redis中以及从Redis中读取还原。 + * @return 返回配置好的带有指定过期时间的Redis缓存配置信息,用于在创建RedisCacheManager或者设置特定缓存键的配置时使用,来定义缓存的具体行为,如数据的序列化和过期策略等。 */ - private Qiniu qiniu; + private RedisCacheConfiguration getRedisCacheConfigurationWithTtl(Integer seconds, RedisSerializer redisSerializer) { + + RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig(); + redisCacheConfiguration = redisCacheConfiguration.serializeValuesWith( + RedisSerializationContext + .SerializationPair + .fromSerializer(redisSerializer) + ).entryTtl(Duration.ofSeconds(seconds)); + + return redisCacheConfiguration; + } /** - * 用于存储阿里大鱼短信平台相关配置信息的属性,阿里大鱼短信平台可用于向用户发送短信通知、验证码等功能, - * 其配置信息包含访问密钥 ID、访问密钥秘密、短信签名等内容,通过该属性能够获取相应配置,进而调用阿里大鱼的短信服务接口来发送短信。 + * 创建并配置RedisTemplate的Bean方法,RedisTemplate是Spring Data Redis提供的用于操作Redis的核心模板类, + * 它封装了与Redis进行交互的常见操作方法,如设置键值对、获取值、操作哈希等数据结构,在这里对其进行了详细的配置,包括设置连接工厂、键和值的序列化器等, + * 使得可以方便地在项目中使用该模板类来操作Redis缓存,实现数据的读写等功能。 + * + * @param redisConnectionFactory 用于创建与Redis服务器连接的工厂类实例,为RedisTemplate提供与Redis服务器通信的连接,是操作Redis的基础依赖,确保能够正确地访问Redis服务器。 + * @param redisSerializer 用于对缓存中存储的对象进行序列化和反序列化的序列化器,用于配置RedisTemplate中值的序列化方式,保证存入Redis的数据和从Redis读取还原的数据格式正确,与整体缓存数据的序列化策略保持一致。 + * @return 返回配置好的RedisTemplate实例,注入到Spring容器中,方便其他组件获取并使用它来进行与Redis缓存相关的各种操作,如向缓存中存入数据、从缓存中获取数据等操作。 */ - private AliDaYu aLiDaYu; + @Bean + public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory, RedisSerializer redisSerializer) { + + RedisTemplate redisTemplate = new RedisTemplate<>(); + redisTemplate.setConnectionFactory(redisConnectionFactory); + redisTemplate.setKeySerializer(new StringRedisSerializer()); + redisTemplate.setHashKeySerializer(new StringRedisSerializer()); + redisTemplate.setValueSerializer(redisSerializer); + redisTemplate.setHashValueSerializer(redisSerializer); + redisTemplate.setEnableTransactionSupport(false); + redisTemplate.afterPropertiesSet(); + return redisTemplate; + } + + /** + * 自定义Redis序列化机制的Bean方法,通过创建一个自定义配置的ObjectMapper实例,对Jackson的序列化和反序列化相关特性进行了一系列配置, + * 目的是为了避免与Spring MVC中默认的ObjectMapper配置产生冲突,同时满足项目中对Redis缓存数据序列化的特定需求,例如对日期时间类型的序列化处理、处理未知属性、空对象以及无效子类型等情况的处理方式, + * 最后基于这个自定义的ObjectMapper创建并返回一个GenericJackson2JsonRedisSerializer实例,用于在Redis缓存中对对象进行序列化和反序列化操作。 + * + * @return 返回配置好的GenericJackson2JsonRedisSerializer实例,作为Redis缓存的序列化器,注入到Spring容器中,供其他与Redis缓存相关的组件(如RedisCacheManager、RedisTemplate等)使用, + * 确保缓存数据能够按照预期的方式进行序列化和反序列化,保证数据的正确存储和读取。 + */ /** - * 用于存储加解密 token 的密钥信息的属性,在涉及用户认证、授权等场景中,token 常用于传递用户身份信息, - * 为了保证 token 的安全性,可能会使用此密钥进行加密和解密操作,该属性保存的密钥值会在相关的加密解密逻辑中被使用。 + * 自定义redis序列化的机制,重新定义一个ObjectMapper.防止和MVC的冲突 + * https://juejin.im/post/5e869d426fb9a03c6148c97e */ - private String tokenAesKey; + @Bean + public RedisSerializer redisSerializer() { + ObjectMapper objectMapper = JsonMapper.builder().disable(MapperFeature.USE_ANNOTATIONS).build(); + // 反序列化时候遇到不匹配的属性并不抛出异常,这样即使缓存数据中存在一些在当前类中没有定义的属性,也能正常进行反序列化操作,提高了兼容性和容错性。 + objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + // 序列化时候遇到空对象不抛出异常,避免因为缓存数据中存在空对象而导致序列化失败的情况,使得空对象也能按照预期进行序列化处理。 + objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false); + // 反序列化的时候如果是无效子类型,不抛出异常,在处理复杂的继承结构或者类型变化时,即使遇到不符合预期的子类型情况,也能继续进行反序列化,增强了反序列化的稳定性。 + objectMapper.configure(DeserializationFeature.FAIL_ON_INVALID_SUBTYPE, false); + // 不使用默认的dateTime进行序列化,避免在处理日期时间类型数据时出现格式不符合项目需求的情况,方便按照项目自定义的方式对日期时间进行序列化。 + objectMapper.configure(SerializationFeature.WRITE_DATE_KEYS_AS_TIMESTAMPS, false); + // 使用JSR310提供的序列化类,里面包含了大量的JDK8时间序列化类,利用Java 8中对日期时间API的优化,更规范、准确地对日期时间类型数据进行序列化和反序列化操作。 + objectMapper.registerModule(new JavaTimeModule()); + // 启用反序列化所需的类型信息,在属性中添加@class,通过这种方式在反序列化时可以明确数据的类型信息,有助于正确还原对象类型,尤其是在处理多态类型数据时非常重要。 + objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL, + JsonTypeInfo.As.PROPERTY); + // 配置null值的序列化器,确保在缓存数据中存在null值时也能正确地进行序列化和反序列化操作,保证数据的完整性和一致性。 + GenericJackson2JsonRedisSerializer.registerNullValueSerializer(objectMapper, null); + return new GenericJackson2JsonRedisSerializer(objectMapper); + } /** - * 用于存储本地文件上传配置信息的属性,本地文件上传配置可能涉及到文件存储路径、文件大小限制、允许的文件类型等相关参数, - * 通过这个属性可以获取相应配置,从而在进行本地文件上传功能实现时,按照配置要求来处理文件上传的各种逻辑,确保文件上传操作符合业务需求。 + * 创建并配置StringRedisTemplate的Bean方法,StringRedisTemplate是Spring Data Redis提供的专门用于操作Redis中字符串类型数据的模板类, + * 相比于RedisTemplate,它更专注于对字符串类型的操作,在这里对其进行了简单配置,设置了禁止事务支持,并返回配置好的实例注入到Spring容器中,方便在项目中对Redis中的字符串数据进行操作, + * 例如存储简单的字符串键值对、执行字符串相关的命令等操作。 + * + * @param redisConnectionFactory 用于创建与Redis服务器连接的工厂类实例,为StringRedisTemplate提供与Redis服务器通信的连接,确保能够正确地访问Redis服务器进行字符串数据的操作。 + * @return 返回配置好的StringRedisTemplate实例,注入到Spring容器中,供其他组件获取并使用它来进行与Redis中字符串类型数据相关的各种操作,方便在项目中处理简单的字符串缓存数据等情况。 */ - private ImgUpload imgUpload; + @Bean + public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) { + StringRedisTemplate redisTemplate = new StringRedisTemplate(redisConnectionFactory); + redisTemplate.setEnableTransactionSupport(false); + return redisTemplate; + } } \ No newline at end of file