使用 AOP 的 @Aspect 注解,实现一个 Redis 缓存注解

前言

  1. 参考别人博客,编写的 Redis 缓存注解
  2. 内含大量注释说明, 复制黏贴即可使用。
  3. 步骤 2-8 为Redis缓存处理,可以单独提出,放入 base 包或 util 包中
  4. 步骤 9-2 为测试使用。

步骤

  1. 参考博客
  2. pom 依赖。需要的依赖文件
  3. application.yml 配置文件。配置 Aop 和 Redis集群
  4. RedisConfig 类。 RedisTemplate 实列化配置文件。
  5. RedisUtil 类。相关 Redis 操作的工具类。
  6. RedisCacheAnnotation 注解。缓存注解,用在需要缓存的方法上。
  7. RedisCacheAop 类。核心业务处理类,确定从缓存中读取数据 或 执行方法写入缓存。
  8. RedisCacheAopConfig 类。 RedisCacheAop 的实列化配置类。
  9. TestController 类。测试用的 Controller 层类。
  10. TestService 类。测试用的 Service 层类。
  11. User 类。实体类
  12. SpringBootMain 类。主启动类。

1.参考博客

https://blog.csdn.net/andybegin/article/details/114303205

2. pom 依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>Spring-mock</artifactId>
    <version>1.0-SNAPSHOT</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.2.RELEASE</version>
        <relativePath/>
    </parent>

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

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

        <!--连接池依赖-->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
    </dependencies>
</project>

3. application.yml 配置文件

spring:
  aop:
    auto: true
    proxy-target-class: false
  redis:
    #    host: 10.2.98.64
    #    port: 6379
    database: 0 #数据库索引(默认为0),如果设置为1,那么存入的key-value都存放在select 1中
    password: Aldx@2018
    timeout: 30000ms #连接超时时间(毫秒)
    lettuce:
      pool:
        max-active: 1000 #连接池最大连接数(使用负值表示没有限制)
        max-wait: 300ms #连接池最大阻塞等待时间(使用负值表示没有限制)
        max-idle: 100 #连接池中的最大空闲连接
        minIdle: 8  #连接池中的最小空闲连接
    cluster:
      nodes:
        - 10.2.98.65:6377
        - 10.2.98.65:6378
        - 10.2.98.65:6379

4. RedisConfig 类

package com.jtfr.config;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
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.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

/**
 * 实例化 RedisTemplate 对象
 */
@Configuration
public class RedisConfig {

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
        // 我们为了自己开发方便,一般直接使用 <String, Object >
        RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
        template.setConnectionFactory(factory);

        //对象映射处理模型
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        // 解决jackson2无法反序列化LocalDateTime的问题
        objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
        objectMapper.registerModule(new JavaTimeModule());

        // 序列化的对象
        StringRedisSerializer keySerializer = new StringRedisSerializer();
        Jackson2JsonRedisSerializer valueSerializer = new Jackson2JsonRedisSerializer(Object.class);
        valueSerializer.setObjectMapper(objectMapper);

        // key采用String的序列化方式
        template.setKeySerializer(keySerializer);
        template.setHashKeySerializer(keySerializer);

        // value序列化 方式采用jackson
        template.setValueSerializer(valueSerializer);
        template.setHashValueSerializer(valueSerializer);

        //设置
        template.afterPropertiesSet();
        return template;
    }
}

5. RedisUtil 类

package com.jtfr.util;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * Redis 操作的工具类
 */
@Component
public class RedisUtil {

    private static final Logger logger = LoggerFactory.getLogger(RedisUtil.class);

    @Resource
    RedisTemplate<String, Object> redisTemplate;

    // =============================common============================

    /**
     * 指定缓存失效时间
     *
     * @param key  键
     * @param time 时间(秒)
     * @return
     */
    public boolean expire(String key, long time) {
        try {
            if (time > 0) {
                redisTemplate.expire(key, time, TimeUnit.SECONDS);
            }
            return true;
        } catch (Exception e) {
            logger.info(e.getMessage());
            return false;
        }
    }

    /**
     * 根据key 获取过期时间
     *
     * @param key 键 不能为null
     * @return 时间(秒) 返回0代表为永久有效
     */
    public long getExpire(String key) {
        return redisTemplate.getExpire(key, TimeUnit.SECONDS);
    }

    /**
     * 判断key是否存在
     *
     * @param key 键
     * @return true 存在 false不存在
     */
    public boolean hasKey(String key) {
        try {
            return redisTemplate.hasKey(key);
        } catch (Exception e) {
            logger.info(e.getMessage());
            return false;
        }
    }

    /**
     * 删除缓存
     *
     * @param key 可以传一个值 或多个
     */
    @SuppressWarnings("unchecked")
    public void del(String... key) {
        if (key != null && key.length > 0) {
            if (key.length == 1) {
                redisTemplate.delete(key[0]);
            } else {
                redisTemplate.delete(CollectionUtils.arrayToList(key));
            }
        }
    }

    // ============================String=============================

    /**
     * 普通缓存获取
     *
     * @param key 键
     * @return 值
     */
    public Object get(String key) {
        return key == null ? null : redisTemplate.opsForValue().get(key);
    }

    /**
     * 普通缓存放入
     *
     * @param key   键
     * @param value 值
     * @return true成功 false失败
     */
    public boolean set(String key, Object value) {
        try {
            redisTemplate.opsForValue().set(key, value);
            return true;
        } catch (Exception e) {
            logger.info("set error={}", e.getMessage());
            return false;
        }

    }

    /**
     * 普通缓存放入并设置时间
     *
     * @param key   键
     * @param value 值
     * @param time  时间(秒) time要大于0 如果time小于等于0 将设置无限期
     * @return true成功 false 失败
     */
    public boolean set(String key, Object value, long time) {
        try {
            if (time > 0) {
                redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
            } else {
                set(key, value);
            }
            return true;
        } catch (Exception e) {
            logger.info(e.getMessage());
            return false;
        }
    }

    /**
     * 递增
     *
     * @param key   键
     * @param delta 要增加几(大于0)
     * @return
     */
    public long incr(String key, long delta) {
        if (delta < 0) {
            logger.info("递增因子必须大于0");

            return 0;
        }
        return redisTemplate.opsForValue().increment(key, delta);
    }

    /**
     * 递减
     *
     * @param key   键
     * @param delta 要减少几(小于0)
     * @return
     */
    public long decr(String key, long delta) {
        if (delta < 0) {
            logger.info("递减因子必须大于0");

            return 0;
        }
        return redisTemplate.opsForValue().increment(key, -delta);
    }

    // ================================Map=================================

    /**
     * HashGet
     *
     * @param key  键 不能为null
     * @param item 项 不能为null
     * @return 值
     */
    public Object hget(String key, String item) {
        return redisTemplate.opsForHash().get(key, item);
    }

    /**
     * 获取hashKey对应的所有键值
     *
     * @param key 键
     * @return 对应的多个键值
     */
    public Map<Object, Object> hmget(String key) {
        return redisTemplate.opsForHash().entries(key);
    }

    /**
     * HashSet
     *
     * @param key 键
     * @param map 对应多个键值
     * @return true 成功 false 失败
     */
    public boolean hmset(String key, Map<String, Object> map) {
        try {
            redisTemplate.opsForHash().putAll(key, map);
            return true;
        } catch (Exception e) {
            logger.info(e.getMessage());
            return false;
        }
    }

    /**
     * HashSet 并设置时间
     *
     * @param key  键
     * @param map  对应多个键值
     * @param time 时间(秒)
     * @return true成功 false失败
     */
    public boolean hmset(String key, Map<String, Object> map, long time) {
        try {
            redisTemplate.opsForHash().putAll(key, map);
            if (time > 0) {
                expire(key, time);
            }
            return true;
        } catch (Exception e) {
            logger.info(e.getMessage());
            return false;
        }
    }

    /**
     * 向一张hash表中放入数据,如果不存在将创建
     *
     * @param key   键
     * @param item  项
     * @param value 值
     * @return true 成功 false失败
     */
    public boolean hset(String key, String item, Object value) {
        try {
            redisTemplate.opsForHash().put(key, item, value);
            return true;
        } catch (Exception e) {
            logger.info(e.getMessage());
            return false;
        }
    }

    /**
     * 向一张hash表中放入数据,如果不存在将创建
     *
     * @param key   键
     * @param item  项
     * @param value 值
     * @param time  时间(秒) 注意:如果已存在的hash表有时间,这里将会替换原有的时间
     * @return true 成功 false失败
     */
    public boolean hset(String key, String item, Object value, long time) {
        try {
            redisTemplate.opsForHash().put(key, item, value);
            if (time > 0) {
                expire(key, time);
            }
            return true;
        } catch (Exception e) {
            logger.info(e.getMessage());
            return false;
        }
    }

    /**
     * 删除hash表中的值
     *
     * @param key  键 不能为null
     * @param item 项 可以使多个 不能为null
     */
    public void hdel(String key, Object... item) {
        redisTemplate.opsForHash().delete(key, item);
    }

    /**
     * 判断hash表中是否有该项的值
     *
     * @param key  键 不能为null
     * @param item 项 不能为null
     * @return true 存在 false不存在
     */
    public boolean hHasKey(String key, String item) {
        return redisTemplate.opsForHash().hasKey(key, item);
    }

    /**
     * hash递增 如果不存在,就会创建一个 并把新增后的值返回
     *
     * @param key  键
     * @param item 项
     * @param by   要增加几(大于0)
     * @return
     */
    public double hincr(String key, String item, double by) {
        return redisTemplate.opsForHash().increment(key, item, by);
    }

    /**
     * hash递减
     *
     * @param key  键
     * @param item 项
     * @param by   要减少记(小于0)
     * @return
     */
    public double hdecr(String key, String item, double by) {
        return redisTemplate.opsForHash().increment(key, item, -by);
    }

    // ============================set=============================

    /**
     * 根据key获取Set中的所有值
     *
     * @param key 键
     * @return
     */
    public Set<Object> sGet(String key) {
        try {
            return redisTemplate.opsForSet().members(key);
        } catch (Exception e) {
            logger.info(e.getMessage());
            return new HashSet<>();
        }
    }

    /**
     * 根据value从一个set中查询,是否存在
     *
     * @param key   键
     * @param value 值
     * @return true 存在 false不存在
     */
    public boolean sHasKey(String key, Object value) {
        try {
            return redisTemplate.opsForSet().isMember(key, value);
        } catch (Exception e) {
            logger.info(e.getMessage());
            return false;
        }
    }

    /**
     * 将数据放入set缓存
     *
     * @param key    键
     * @param values 值 可以是多个
     * @return 成功个数
     */
    public long sSet(String key, Object... values) {
        try {
            return redisTemplate.opsForSet().add(key, values);
        } catch (Exception e) {
            logger.info(e.getMessage());
            return 0;
        }
    }

    /**
     * 将set数据放入缓存
     *
     * @param key    键
     * @param time   时间(秒)
     * @param values 值 可以是多个
     * @return 成功个数
     */
    public long sSetAndTime(String key, long time, Object... values) {
        try {
            Long count = redisTemplate.opsForSet().add(key, values);
            if (time > 0) {
                expire(key, time);
            }
            return count;
        } catch (Exception e) {
            logger.info(e.getMessage());
            return 0;
        }
    }

    /**
     * 获取set缓存的长度
     *
     * @param key 键
     * @return
     */
    public long sGetSetSize(String key) {
        try {
            return redisTemplate.opsForSet().size(key);
        } catch (Exception e) {
            logger.info(e.getMessage());
            return 0;
        }
    }

    /**
     * 移除值为value的
     *
     * @param key    键
     * @param values 值 可以是多个
     * @return 移除的个数
     */
    public long setRemove(String key, Object... values) {
        try {
            return redisTemplate.opsForSet().remove(key, values);
        } catch (Exception e) {
            logger.info(e.getMessage());
            return 0;
        }
    }
    // ===============================list=================================

    /**
     * 获取list缓存的内容
     *
     * @param key   键
     * @param start 开始
     * @param end   结束 0 到 -1代表所有值
     * @return
     */
    public List<Object> lGet(String key, long start, long end) {
        try {
            return redisTemplate.opsForList().range(key, start, end);
        } catch (Exception e) {
            logger.info(e.getMessage());
            return new ArrayList<>();
        }
    }

    /**
     * 获取list缓存的长度
     *
     * @param key 键
     * @return
     */
    public long lGetListSize(String key) {
        try {
            return redisTemplate.opsForList().size(key);
        } catch (Exception e) {
            logger.info(e.getMessage());
            return 0;
        }
    }

    /**
     * 通过索引 获取list中的值
     *
     * @param key   键
     * @param index 索引 index>=0时, 0 表头,1 第二个元素,依次类推;index<0时,-1,表尾,-2倒数第二个元素,依次类推
     * @return
     */
    public Object lGetIndex(String key, long index) {
        try {
            return redisTemplate.opsForList().index(key, index);
        } catch (Exception e) {
            logger.info(e.getMessage());
            return null;
        }
    }

    /**
     * 将list放入缓存
     *
     * @param key   键
     * @param value 值
     * @return
     */
    public boolean lSet(String key, Object value) {
        try {
            redisTemplate.opsForList().rightPush(key, value);
            return true;
        } catch (Exception e) {
            logger.info(e.getMessage());
            return false;
        }
    }

    /**
     * 将list放入缓存
     *
     * @param key   键
     * @param value 值
     * @param time  时间(秒)
     * @return
     */
    public boolean lSet(String key, Object value, long time) {
        try {
            redisTemplate.opsForList().rightPush(key, value);
            if (time > 0) {
                expire(key, time);
            }
            return true;
        } catch (Exception e) {
            logger.info(e.getMessage());
            return false;
        }
    }

    /**
     * 将list放入缓存
     *
     * @param key   键
     * @param value 值
     * @return
     */
    public boolean lSet(String key, List<Object> value) {
        try {
            redisTemplate.opsForList().rightPushAll(key, value);
            return true;
        } catch (Exception e) {
            logger.info(e.getMessage());
            return false;
        }
    }

    /**
     * 将list放入缓存
     *
     * @param key   键
     * @param value 值
     * @param time  时间(秒)
     * @return
     */
    public boolean lSet(String key, List<Object> value, long time) {
        try {
            redisTemplate.opsForList().rightPushAll(key, value);
            if (time > 0) {
                expire(key, time);
            }
            return true;
        } catch (Exception e) {
            logger.info(e.getMessage());
            return false;
        }
    }

    /**
     * 根据索引修改list中的某条数据
     *
     * @param key   键
     * @param index 索引
     * @param value 值
     * @return
     */
    public boolean lUpdateIndex(String key, long index, Object value) {
        try {
            redisTemplate.opsForList().set(key, index, value);
            return true;
        } catch (Exception e) {
            logger.info(e.getMessage());
            return false;
        }
    }

    /**
     * 移除N个值为value
     *
     * @param key   键
     * @param count 移除多少个
     * @param value 值
     * @return 移除的个数
     */
    public long lRemove(String key, long count, Object value) {
        try {
            return redisTemplate.opsForList().remove(key, count, value);
        } catch (Exception e) {
            logger.info(e.getMessage());
            return 0;
        }
    }
}

6. RedisCacheAnnotation 注解

package com.jtfr.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * Redis缓存注解
 */
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface RedisCacheAnnotation {

    // 缓存key
    String key() default "";

    // 是否追加额外参数的值到key后面
    String[] extraKey() default {};

    // 过期时间,默认1小时
    int expiredTime() default 3600;
}

7. RedisCacheAop 类

package com.jtfr.aop;

import com.jtfr.annotation.RedisCacheAnnotation;
import com.jtfr.util.RedisUtil;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import java.lang.reflect.Field;

/**
 * 核心操作 Redis 缓存注解的 切片方法,拦截执行,确认是否要执行。
 * @Configuration 自动
 */
@Aspect
public class RedisCacheAop {

    private static final Logger logger = LoggerFactory.getLogger(RedisCacheAop.class);
    private static final String SEP_SIGNAL = ":";

    @Autowired
    RedisUtil redisUtil;

    /**
     * 环绕通知,对指定的注解,
     * @param ProceedingJoinPoint,获取 注解的参数信息 和 目标方法 的数据。
     * @param pjp
     * @return
     * @throws Throwable
     */
    @Around(value = "@annotation(com.jtfr.annotation.RedisCacheAnnotation)")
    public Object run(ProceedingJoinPoint pjp) throws Throwable {
        // 获取方法签名(getSignature()) -> 方法信息
        MethodSignature methodSignature = (MethodSignature) pjp.getSignature();
        // methodSignature -> 获取方法(getMethod()) -> 获取方法指定注解(getDeclaredAnnotation(RedisCacheAnnotation.class))
        RedisCacheAnnotation redisCacheAnnotation = methodSignature.getMethod().getDeclaredAnnotation(RedisCacheAnnotation.class);

        // 获取注解上参数
        String key = redisCacheAnnotation.key();
        int expiredTime = redisCacheAnnotation.expiredTime();
        String[] extraKey = redisCacheAnnotation.extraKey();

        // 如果存在追加在key,则获取
        if (extraKey.length > 0) {
            StringBuilder extraKeySB = new StringBuilder();
            // 获取方法的"形参"列表
            String[] parameterNames = methodSignature.getParameterNames();
            // 获取传入方法的"实参"列表
            Object[] args = pjp.getArgs();
            /**
             * 遍历:用 extraKey 指定的参数,获取值。
             * 案例:
             *  1. 获取方法参数的值。extraKey={"id","name"} + method(String id,String name, String desc) = 获取 method 里面的 id 和 name 的值。
             *  2. 方法参数对象的类型。extraKey={"id","name"}  +  method(User user) = 获取 user 里面 id 和 name 两个字段的值。
             */
            for (String s : extraKey) {
                // 如果是DTO,则通过反射拿数据
                if (checkIsDTO(extraKey, parameterNames)) {
                    // 获取"形参"列表的 DTO,只支持第一个 DTO 的情况。
                    Object dtoObj = args[0];
                    // 获取 "形参" 的类 class 对象
                    Class<?> aClass = dtoObj.getClass();
                    // 参数类字节码中,反射获取指定字段
                    Field field = aClass.getDeclaredField(s);
                    // 允许访问私有字段
                    field.setAccessible(true);
                    // 获取 字段 值,拼接到 key 中
                    String tmp = SEP_SIGNAL + field.get(dtoObj);
                    extraKeySB.append(tmp);
                } else {
                    /**
                     * 遍历:获取指定 参数 的值,拼接到 key 中
                     */
                    for (int i = 0; i < parameterNames.length; i++) {
                        if (parameterNames[i].equals(s)) {
                            String tmp = SEP_SIGNAL + args[i];
                            extraKeySB.append(tmp);
                            // 参数名称不能相同,最多只会有一个,所以 break;
                            break;
                        }
                    }
                }
            }

            key += extraKeySB.toString();
        }

        // Redis 中读取数据
        Object o = redisUtil.get(key);
        /**
         * 1. 没有获取数据 -> 执行方法获得结果 -> 缓存结果到 Redis 中 -> 响应结果
         * 2. Redis中获取到数据 -> 响应结果
         */
        if (null == o) {
            // 执行原方法
            Object obj = pjp.proceed();
            redisUtil.set(key, obj, expiredTime);
            logger.info("执行方法, 缓存数据, 缓存key={}, 过期时间={}", key, expiredTime);
            return obj;
        } else {
            logger.info("不执行方法,从Redis缓存中获取数据,缓存key={}", key);
            return o;
        }
    }


    /**
     * 检查输入的参数是 DTO 类型 还是 简单类型(基本类型 和 String 类型)
     * 如果传入的 extraKey 都不存在于 params, 就当做传入的参数是一个DTO对象
     *
     * @return
     */
    private static boolean checkIsDTO(String[] extraKey, String[] params) {
        for (String s : extraKey) {
            for (String param : params) {
                if (param.equals(s)) {
                    return false;
                }
            }
        }

        return true;
    }
}

8. RedisCacheAopConfig 类

package com.jtfr.config;

import com.jtfr.aop.RedisCacheAop;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * 实例化 RedisCacheAop 对象
 */
@Configuration
public class RedisCacheAopConfig {

    @Bean
    public RedisCacheAop redisCacheAop(){
        return new RedisCacheAop();
    }

}

9. TestController 类

package com.jtfr.controller;

import com.jtfr.entity.User;
import com.jtfr.service.TestService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/test")
public class TestController {

    @Autowired
    private TestService testService;

    @GetMapping("/get")
    public String get(){
        User user = new User();
        user.setId("1");
        user.setName("jtfr");
        user.setAge(10);
        return testService.readUser(user);
    }

    @GetMapping("/get2")
    public String test(){
        return testService.test("2", "haode", "老铁没毛病");
    }
}

10. TestService 类

package com.jtfr.service;

import com.jtfr.annotation.RedisCacheAnnotation;
import com.jtfr.entity.User;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

@Service
public class TestService {

    private static final Logger logger = LoggerFactory.getLogger(TestService.class);

    @RedisCacheAnnotation(key = "CacheKey", extraKey = {"id", "name"}, expiredTime = 3)
    public String readUser(User user){
        logger.info("执行了 TestService.readUser(), user.toString() = {}", user.toString());
        return "TestService.readUser() 的 Value";
    }

    @RedisCacheAnnotation(key = "CacheKey", extraKey = {"id", "name"}, expiredTime = 3)
    public String test(String id, String name, String desc){
        logger.info("执行了 TestService.test(), id={}, name={}, desc={}", id, name, desc);
        return "TestService.test() 的 Value";
    }
}

11. User 类

package com.jtfr.entity;

public class User {

    private String id;
    private String name;
    private Integer age;

    public String getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

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

12. SpringBootMain 类

package com.jtfr;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SpringBootMain {

    /**
     * 1. RedisUtil 没有仔细看
     * 2. Redis 集群,改成单机执行
     * @param args
     */
    public static void main(String[] args) {
        SpringApplication.run(SpringBootMain.class, args);
    }

}
Aspect-Cache-Plug先介绍缓存使用下场景对同一请求(针对不同请求参数)进行缓存,可以减少服务器压力、加快响应速度查询接口:根据请求条件对返回结果进行缓存更新接口:根据条件对指定缓存进行清除@Aspect(key = "query") public Object query(String q) {   // do something   return null; }@Aspect(key = "update") public Object update(String q) {   // do something     return null; }缓存query方法返回值<bean class="com.aspect.config.CacheConfig">     <property name="key" value="query"/>     <property name="space" value="space2"/>     <property name="keyExpression">         <value>this[0] new java.util.Date()</value>     </property>                      <property name="timeout" value="60"/> </bean>执行update时清除query的返回结果<bean class="com.aspect.config.ClearConfig">     <property name="key" value="update"/>         <property name="cachedConfigs">         <list>             <value>query</value>         </list>     </property> </bean>加入spring支持<aop:config>          <aop:pointcut id="adviceAspectPoint" expression="execution(* com.sample..*.*(..)) and @annotation(Aspect)" />          <aop:aspect ref="adviceAspect">              <aop:around method="execute" pointcut-ref="adviceAspectPoint" arg-names="Aspect" />         </aop:aspect>      </aop:config>     <bean id="adviceAspect" class="com.aspect.AdviceAspect">         <property name="rootKey" value="aspect.cache."/>         <property name="cache" ref="cache"/>         <property name="caches">             <list>                 <bean class="com.aspect.config.CacheConfig">                     <property name="key" value="queryMethod1"/>                     <property name="space" value="space1"/>                     <property name="keyExpression">                         <value>this[1] "." this[2]</value>                     </property>                     <property name="domainExpression">                         <value>this[0]</value>                     </property>                     <property name="timeout" value="60"/>                 </bean>                 <bean class="com.aspect.config.CacheConfig">                     <property name="key" value="queryMethod2"/>                     <property name="space" value="space1"/>                     <property name="keyExpression">                         <value>this[0]</value>                     </property>                                      <property name="timeout" value="60"/>                 </bean>                 <bean class="com.aspect.config.CacheConfig">                     <property name="key" value="space2QueryMethod1"/>                     <property name="space" value="space2"/>                     <property name="keyExpression">                         <value>this[0] new java.util.Date()</value>                     </property>                                      <property name="timeout" value="60"/>                 </bean>             </list>         </property>         <property name="clears">             <list>                 <bean class="com.aspect.config.ClearConfig">                     <property name="key" value="updateMethod1"/>                     <property name="domainExpression">                         <value>this[0]</value>                     </property>                     <property name="cachedConfigs">                         <list>                             <value>queryMethod1</value>                             <value>space2QueryMethod1</value>                         </list>                     </property>                 </bean>             </list>         </property>     </bean> 标签:Aspect
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值