SpringCache 框架使用以及序列化和缓存过期时间问题的解决

目录

为什么使用Spring Cache

如何使用Spring Cache

1 加依赖

2 开启缓存

3 加缓存注解

序列化以及过期时间等问题

解决方案:自定义序列化方式

1.自定义序列化方式并设置白名单

2.配置并设置缓存的过期时间


为什么使用Spring Cache

        缓存有诸多的好处,于是大家就摩拳擦掌准备给自己的应用加上缓存的功能。但是网上一搜却发现缓存的框架太多了,各有各的优势,比如Redis、Memcached、Guava、Caffeine等等。
        如果我们的程序想要使用缓存,就要与这些框架耦合。聪明的架构师已经在利用接口来降低耦合了,利用面向对象的抽象和多态的特性,做到业务代码与具体的框架分离。
但我们仍然需要显式地在代码中去调用与缓存有关的接口和方法,在合适的时候插入数据到缓存里,在合适的时候从缓存中读取数据。
        想一想AOP的适用场景,这不就是天生就应该AOP去做的吗?

        是的,Spring Cache就是一个这个框架。它利用了AOP,实现了基于注解的缓存功能,并且进行了合理的抽象,业务代码不用关心底层是使用了什么缓存框架,只需要简单地加一个注解,就能实现缓存功能了。而且Spring Cache也提供了很多默认的配置,用户可以3秒钟就使用上一个很不错的缓存功能。

如何使用Spring Cache

        上面的3秒钟,绝对不夸张。使用SpringCache分为很简单的三步:加依赖,开启缓存,加缓存注解。

1 加依赖

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-cache</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <!--json依赖-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.76</version>
        </dependency>

2 开启缓存

在启动类加上@EnableCaching注解即可开启使用缓存。

@Slf4j
@SpringBootApplication
@EnableCaching
public class WaiMaiApplication {
    public static void main(String[] args) {
        SpringApplication.run(WaiMaiApplication.class,args);
        log.info("项目启动成功!123");
    }
}

3 加缓存注解

spring boot cache 提供了一些注解方便做cache应用。

(1)@CacheConfig:主要用于配置该类中会用到的一些共用的缓存配置

(2)@Cacheable:主要方法返回值加入缓存。同时在查询时,会先从缓存中取,若不存在才再发起对数据库的访问。

(3)@CachePut:配置于函数上,能够根据参数定义条件进行缓存,与@Cacheable不同的是,每次回真实调用函数,所以主要用于数据新增和修改操作上。

(4)@CacheEvict:配置于函数上,通常用在删除方法上,用来从缓存中移除对应数据

(5)@Caching:配置于函数上,组合多个Cache注解使用。


例子:

    /**
     * 根据条件查询套餐数据 在查询到数据的同时向redis添加缓存
     * @param setmeal
     * @return
     */
    @GetMapping("/list")
    @Cacheable(cacheNames= "setmealCache",key = "#setmeal.categoryId+'_'+#setmeal.status" )
    public R<List<Setmeal>> list(Setmeal setmeal){
        LambdaQueryWrapper<Setmeal> queryWrapper=new LambdaQueryWrapper<>();
        queryWrapper.eq(setmeal.getCategoryId()!=null,Setmeal::getCategoryId,setmeal.getCategoryId())
                    .eq(setmeal.getStatus()!=null,Setmeal::getStatus,setmeal.getStatus())
                    .orderByDesc(Setmeal::getUpdateTime);
        List<Setmeal> setmealList = setmealService.list(queryWrapper);

        return R.success(setmealList);
    }

   /**
     * 删除套餐 更改数据库数据后同时删除缓存
     * @param ids
     * @return
     */
    @DeleteMapping
    @CacheEvict(value = "setmealCache",allEntries = true)
    public R<String> delete(Long[] ids){
        log.info("ids:{}",ids);
        setmealService.removeWithDish(ids);
        return R.success("套餐数据删除成功!");
    }

序列化以及过期时间等问题

在设置缓存注解后,添加到Redis的缓存数据是用StringRedisSerializer和JdkSerializationRedisSerialize为序列话策略,JdkSerializationRedisSerialize非常好,但是其序列化的结果是一堆子节码,这给我们阅读带来了麻烦。

解决方案:自定义序列化方式

我们这里自定义了FastJsonRedisSerializer 序列化对象后缓存到redis,可以更 方便的观察缓存数据。

1.自定义序列化方式并设置白名单
package com.songqiao.waimai.config;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.parser.ParserConfig;
import com.alibaba.fastjson.serializer.SerializerFeature;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.SerializationException;

import java.nio.charset.Charset;

/**
 * 说明:自定义redis序列化方式
 *
 * @author Songqiao
 * @version V1.0
 * @since 2023.07.24
 */
public class FastJsonRedisSerializer<T> implements RedisSerializer<T> {

    public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");

    private Class<T> clazz;
    //添加白名单 防止反序列化错误 反序列化报错 com.alibaba.fastjson.JSONException: autoType is not support
    static {
        ParserConfig.getGlobalInstance().addAccept("com.songqiao.waimai");
    }

    public FastJsonRedisSerializer(Class<T> clazz) {
        super();
        this.clazz = clazz;
    }

    @Override
    public byte[] serialize(T t) throws SerializationException {
        if (t == null) {
            return new byte[0];
        }
        return JSON.toJSONString(t, SerializerFeature.WriteClassName).getBytes(DEFAULT_CHARSET);
    }

    @Override
    public T deserialize(byte[] bytes) throws SerializationException {
        if (bytes == null || bytes.length <= 0) {
            return null;
        }
        String str = new String(bytes, DEFAULT_CHARSET);
        return JSON.parseObject(str, clazz);
    }
}
2.配置并设置缓存的过期时间
package com.songqiao.waimai.config;

import org.springframework.cache.annotation.CachingConfigurerSupport;
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.serializer.RedisSerializationContext;

import java.time.Duration;

/**
 *
 * @author Songqiao
 * @version V1.0
 * @since 2023.07.24
 */
@Configuration
@EnableCaching
public class MyCacheConfig extends CachingConfigurerSupport {
    /**
     *  设置 redis 数据默认过期时间
     *  设置@cacheable 序列化方式
     * @return
     */
    @Bean
    public RedisCacheConfiguration redisCacheConfiguration(){
        FastJsonRedisSerializer<Object> fastJsonRedisSerializer = new FastJsonRedisSerializer<>(Object.class);
        RedisCacheConfiguration configuration = RedisCacheConfiguration.defaultCacheConfig();

        configuration = configuration.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(fastJsonRedisSerializer)).entryTtl(Duration.ofDays(30));
        return configuration;
    }
}

注解方式实现缓存、以及序列化等相关问题已解决!

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Spring Security OAuth2中,缓存的处理可以使用Jackson进行序列化。具体实现步骤如下: 1. 添加Jackson依赖 在pom.xml文件中添加以下依赖: ```xml <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> </dependency> ``` 2. 实现序列化器 创建一个自定义的序列化器,继承自`JsonSerializer`: ```java public class OAuth2AccessTokenSerializer extends JsonSerializer<OAuth2AccessToken> { @Override public void serialize(OAuth2AccessToken token, JsonGenerator gen, SerializerProvider serializers) throws IOException, JsonProcessingException { gen.writeStartObject(); gen.writeStringField("value", token.getValue()); gen.writeNumberField("expiration", token.getExpiration().getTime()); // 其他字段序列化 gen.writeEndObject(); } } ``` 3. 注册序列化器 在配置类中注册序列化器: ```java @Configuration public class JacksonConfiguration { @Bean public ObjectMapper objectMapper() { ObjectMapper objectMapper = new ObjectMapper(); SimpleModule module = new SimpleModule(); module.addSerializer(OAuth2AccessToken.class, new OAuth2AccessTokenSerializer()); objectMapper.registerModule(module); return objectMapper; } } ``` 4. 配置缓存缓存配置类中,指定序列化器: ```java @Configuration @EnableCaching public class CacheConfiguration extends CachingConfigurerSupport { @Autowired private ObjectMapper objectMapper; @Bean public CacheManager cacheManager(RedisConnectionFactory connectionFactory) { RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig() .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new Jackson2JsonRedisSerializer<>(OAuth2AccessToken.class, objectMapper))); return RedisCacheManager.builder(connectionFactory) .cacheDefaults(config) .build(); } } ``` 这样就可以使用Jackson进行缓存序列化了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

龙城桥少

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值