微服务架构-5-Redis实战-5-SpringBoot整合Redis缓存注解开发

redis缓存注解

在这里插入图片描述

Spring Boot缓存注解@Cacheable@CacheEvict@CachePut使用
@Cacheable(查询)
@CachePut(新增修改)
@CacheEvict(清空缓存)

一.概念

Spring Boot缓存注解@Cacheable、@CacheEvict、@CachePut使用

1@Cacheable
可以标记在一个方法上,也可以标记在一个类上。当标记在一个方法上时表示该方法是支持缓存的,当标记在一个类上时则表示该类所有的方法都是支持缓存的。对于一个支持缓存的方法,Spring会在其被调用后将其返回值缓存起来,以保证下次利用同样的参数来执行该方法时可以直接从缓存中获取结果,而不需要再次执行该方法。

@Cacheable可以指定三个属性,value、key和condition。
参数解释example
value缓存的名称,在 spring 配置文件中定义,必须指定至少一个例如: @Cacheable(value=”mycache”) @Cacheable(value={”cache1”,”cache2”}
key缓存的 key,可以为空,如果指定要按照 SpEL 表达式编写,如果不指定,则缺省按照方法的所有参数进行组合@Cacheable(value=”testcache”,key=”#userName”)
condition缓存的条件,可以为空,使用 SpEL 编写,返回 true 或者 false,只有为 true 才进行缓存@Cacheable(value=”testcache”,condition=”#userName.length()>2”)
除了上述使用方法参数作为key之外,Spring还为我们提供了一个root对象可以用来生成key。通过该root对象我们可以获取到以下信息。
属性名称描述示例
methodName当前方法名#root.methodName
method当前方法#root.method.name
target当前被调用的对象#root.target
targetClass当前被调用的对象的class#root.targetClass
args当前方法参数组成的数组#root.args[0]
caches当前被调用的方法使用的Cache#root.caches[0].name
当我们要使用root对象的属性作为key时我们也可以将“#root”省略,因为Spring默认使用的就是root对象的属性。

2、 @CachePut

 @CachePut标注的方法在执行前不会去检查缓存中是否存在之前执行过的结果,而是每次都会执行该方法,并将执行结果以键值对的形式存入指定的缓存中。

3、@CacheEvict

@CacheEvict是用来标注在需要清除缓存元素的方法或类上的。当标记在一个类上时表示其中所有的方法的执行都会触发缓存的清除操作。@CacheEvict可以指定的属性有value、key、condition、allEntries和beforeInvocation。其中value、key和condition的语义与@Cacheable对应的属性类似。

allEntries是boolean类型,表示是否需要清除缓存中的所有元素。默认为false。

beforeInvocation属性:清除操作默认是在对应方法成功执行之后触发的,即方法如果因为抛出异常而未能成功返回时也不会触发清除操作。使用beforeInvocation可以改变触发清除操作的时间,当我们指定该属性值为true时,Spring会在调用该方法之前清除缓存中的指定元素。

    /**
     * 清除缓存
     * allEntries = true:是否清除所有的缓存,默认值false
     * beforeInvocation:是否在方法执行之前清除缓存,默认在方法执行完成后清除缓存
     * @param id
     */
    @CacheEvict(value = "user",key = "#id",allEntries = true,beforeInvocation = true)
    @RequestMapping("deleteCache")
    public void deleteCache(Integer id){
        System.out.println("-------deleteCache--------");
    }

二.缓存编程

1 配置文件application.yml

spring:
  redis:
    host: 116.62.68.112
    password: 123456
    port: 6379
    database: 1

####swagger相关配置
swagger:
  base-package: com.chenyun
  title: redis-demo
  description: redis
  version: 1.1
  terms-of-service-url: www.bajin.com
  contact:
    name: 80后互联网架构师-金霖海
    email: 2559226091@qq.com
2.在启动类上开启SpringBoot对缓存的支持
	@EnableCaching
3.在需要缓存的类或者方法上加缓存注解 @Cacheable
	方法的返回值会被以缓存的形式存储到redis中

相关代码

User类

package com.chenyun.pojo;

import java.io.Serializable;

public class User implements Serializable {
    private Integer id;
    private String name;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public User() {
    }

    public User(Integer id, String name) {
        this.id = id;
        this.name = name;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
}

CacheController

package com.chenyun.web;

import com.chenyun.pojo.User;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.List;

@RestController
public class CacheController {

    @Cacheable(value = "getUser")
    @PostMapping("getUser")
    public List<User> getUser(User user){
        System.out.println("--------------getUser");
        User user1 = new User(1, "赵日天");
        User user2 = new User(2, "李杀神");
        User user3 = new User(3, "刘斩仙");
        ArrayList<User> arrayList = new ArrayList<>();
        arrayList.add(user1);
        arrayList.add(user2);
        arrayList.add(user3);
        return arrayList;
    }

    @Cacheable(value = "getUserById",key = "#user.id")
    @PostMapping("getUserById")
    public List<User> getUserById(@RequestBody User user){
        System.out.println("--------------getUserById");
        User user1 = new User(1, "赵日天");
        User user2 = new User(2, "李杀神");
        User user3 = new User(3, "刘斩仙");
        ArrayList<User> arrayList = new ArrayList<>();
        arrayList.add(user1);
        arrayList.add(user2);
        arrayList.add(user3);
        return arrayList;
    }

    /**
     * 根据主键查询用户信息
     */
    @Cacheable(value = "user",key = "#id")
    @PostMapping("getUserById/{id}")
    public User getUserById(@PathVariable("id") Integer id){
        System.out.println("------------getUserById");
        User user1 = new User(1, "赵日天");
        User user2 = new User(2, "李杀神");
        User user3 = new User(3, "刘斩仙");
        if(id == 1){
            return user1;
        }else if(id == 2){
            return user2;
        }else if(id == 3) {
            return user3;
        }
        return null;
    }


    /**
     * 取多个参数作为组合键
     * @param idOne
     * @param idTwo
     * @return
     */
    @Cacheable(value = "user",key = "#idOne+#idTwo")
    @PostMapping("getUserById2/{id1}/{id2}")
    public List<User> getUserById2(@PathVariable("id1") String idOne, @PathVariable("id2") String idTwo){
        System.out.println("--------------getUserById:"+idOne+"-"+idTwo);
        User user1 = new User(1, "赵日天");
        User user2 = new User(2, "李杀神");
        User user3 = new User(3, "刘斩仙");
        ArrayList<User> arrayList = new ArrayList<>();
        arrayList.add(user1);
        arrayList.add(user2);
        arrayList.add(user3);
        return arrayList;
    }

    /**
     * 取多个参数作为组合键
     * @param idOne
     * @param idTwo
     * @return
     */
    @Cacheable(value = "user",key = "{#idOne,#idTwo}",condition="#idOne=='2'")
    @PostMapping("getUserById3/{id1}/{id2}")
    public List<User> getUserById3(@PathVariable("id1") Integer idOne,@PathVariable("id2") Integer idTwo){
        System.out.println("--------------getUserById:"+idOne+"-"+idTwo);
        User user1 = new User(1, "赵日天");
        User user2 = new User(2, "李杀神");
        User user3 = new User(3, "刘斩仙");
        ArrayList<User> arrayList = new ArrayList<>();
        arrayList.add(user1);
        arrayList.add(user2);
        arrayList.add(user3);
        return arrayList;
    }

    /**
     * 使用root作为组合键
     * @param idOne
     * @param idTwo
     * @return
     */
    @Cacheable(value = "user_root",key = "#root.method")
    @PostMapping("getUserByIdRoot/{id1}/{id2}")
    public List<User> getUserByIdRoot(@PathVariable("id1") String idOne,@PathVariable("id2") String idTwo){
        System.out.println("--------------getUserById:"+idOne+"-"+idTwo);
        User user1 = new User(1, "赵日天");
        User user2 = new User(2, "李杀神");
        User user3 = new User(3, "刘斩仙");
        ArrayList<User> arrayList = new ArrayList<>();
        arrayList.add(user1);
        arrayList.add(user2);
        arrayList.add(user3);
        return arrayList;
    }

    //新增-修改-------------------------------------------------------------------
    @CachePut(value = "user",key = "#user.id")
    @PostMapping("updateUser")
    public User updateUser(@RequestBody User user){
        System.out.println("-----------updateUser");
        return user;
    }

    @CachePut(value = "user",key = "#user.id")
    @PostMapping("add")
    public User add(User user){
        return user;
    }

    @CacheEvict(value = "user",key = "#id")
    @PostMapping("deleteCache/{id}")
    public void deleteCache(@PathVariable("id") Integer id){

    }
}

三 设置缓存有效期

1 配置文件

package com.chenyun.web;


import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.concurrent.ConcurrentMapCacheManager;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
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.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.text.DecimalFormat;
import java.time.Duration;
import java.util.*;
import java.util.stream.Collectors;

@Configuration
public class CacheConfig {


    @Autowired
    private ApplicationContext applicationContext;

    @Autowired
    private RedisConnectionFactory factory;

    @Bean
    @Primary
    RedisCacheManager redisCacheManager() {
        final RedisCacheWriter writer = RedisCacheWriter.nonLockingRedisCacheWriter(factory);
        final GenericJackson2JsonRedisSerializer jackson = new GenericJackson2JsonRedisSerializer();
        final RedisSerializationContext.SerializationPair<Object> pair = RedisSerializationContext.SerializationPair
                .fromSerializer(jackson);
        final RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
                .serializeValuesWith(pair).entryTtl(Duration.ofSeconds(30));
        final Map<String, RedisCacheConfiguration> conf = getConf();
        System.out.println(conf);
        return new RedisCacheManager(writer, config, conf);
    }


    @Bean
    public ConcurrentMapCacheManager cacheManager() {
        ConcurrentMapCacheManager cacheManager = new ConcurrentMapCacheManager();

        return cacheManager;
    }


    private Map<String, RedisCacheConfiguration> getConf() {

        final Map<String, Object> beansWithAnnotation = applicationContext.getBeansWithAnnotation(Component.class);
        final List<CacheMap> collect = beansWithAnnotation.entrySet().stream().flatMap(entry -> {
            try {
                final Object value = entry.getValue();
                // 获得原本的class名字,spring代理的都是后面有$$直接截取即可
                String className = "";
                if (value.getClass().getName().contains("$")){
                    className = value.getClass().getName().
                            substring(0, value.getClass().getName().indexOf("$"));
                }else{
                    className = value.getClass().getName();
                }

                // 获得原始的字节码文件,如果被spring 代理之后,方法上会获取不到注解信息
                final Method[] methods = Class.forName(className)
                        .getDeclaredMethods();

                return Arrays.stream(methods).flatMap(method -> {
                    final Cacheable annotation = method.getAnnotation(Cacheable.class);
                    if (annotation == null) {
                        return null;
                    }
                    return Arrays.stream(annotation.cacheNames()).map(data -> {
                        if (data.contains("#")) {
                            // 包含自定义日期
                            final String[] split = data.split("#");
                            if (split.length != 2) {
                                return null;
                            }
                            final CacheMap cacheMap = new CacheMap();
                            cacheMap.setName(data);
                            final String s = split[1];
                            final int time = Integer.parseInt(s.substring(0, s.length() - 1));
                            if (s.endsWith("s")) {
                                cacheMap.setTtl(Duration.ofSeconds(time));
                            } else if (s.endsWith("m")) {
                                cacheMap.setTtl(Duration.ofMinutes(time));
                            } else if (s.endsWith("d")) {
                                cacheMap.setTtl(Duration.ofDays(time));
                            }
                            return cacheMap;
                        }
                        return null;
                    }).filter(Objects::nonNull);
                });


            } catch (Exception e) {
                System.out.println("异常");
                return null;
            }
        }).collect(Collectors.toList());

        return collect.stream().collect(Collectors.toMap(CacheMap::getName, p -> {
            final GenericJackson2JsonRedisSerializer jackson = new GenericJackson2JsonRedisSerializer();
            final RedisSerializationContext.SerializationPair<Object> pair = RedisSerializationContext.SerializationPair
                    .fromSerializer(jackson);
            return RedisCacheConfiguration.defaultCacheConfig()
                    .serializeValuesWith(pair).entryTtl(p.getTtl());
        }, (key1, key2) -> key2));
    }


    class CacheMap {
        private String name;
        private Duration ttl;

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public Duration getTtl() {
            return ttl;
        }

        public void setTtl(Duration ttl) {
            this.ttl = ttl;
        }
    }
}

2 Controller

package com.chenyun.web;

import com.chenyun.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.concurrent.TimeUnit;

@RestController
public class TimeCacheController{
    @Autowired
    private StringRedisTemplate redisTemplate;


    @PostMapping("getUserByIdTime")
    public User getUserByIdTime(){
        System.out.println("------------getUserById");
        User user1 = new User(1, "赵日天");
        //k v  t  u
        redisTemplate.opsForValue().set("user::1",user1.toString(),1, TimeUnit.MINUTES);
        return user1;
    }

    @Cacheable(value = "user#30s",key = "#id")
    @PostMapping("getUserByIdTime/{id}")
    public User getUserByIdTime(@PathVariable("id") Integer id){
        System.out.println("------------getUserById");
        User user1 = new User(1, "赵日天");
        User user2 = new User(2, "李杀神");
        User user3 = new User(3, "刘斩仙");
        if(id == 1){
            return user1;
        }else if(id == 2){
            return user2;
        }else if(id == 3) {
            return user3;
        }
        return null;
    }

}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值