springboot增加注解缓存@Cacheable的实现

目录
  • springboot增加注解缓存@Cacheable
    • 业务层使用
    • 配置
  • @Cacheable注解的属性使用
    • cacheNames和value
    • key
    • keyGenerator
    • keyGenerator
    • condition
    • unless(除非)
    • sync

springboot增加注解缓存@Cacheable

业务层使用

@Cacheable(value = "dictionary#1800", key = "#root.targetClass.simpleName +':'+ #root.methodName +':'+ #code")
    public Object findByCode(String code) {
        //业务
    }

配置

import org.springframework.cache.Cache;
import org.springframework.data.redis.cache.RedisCache;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.core.RedisOperations;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

public class MyRedisCacheManager extends RedisCacheManager {
    /**
     * 过期时间分隔符
     */
    private static final String TTLSEPARATOR = "#";
    private final ConcurrentMap<String, Cache> cacheMap = new ConcurrentHashMap(16);
    /**
     * 过期时间, 单位为 秒
     */
    private long defaultExpiration = 0;
    public MyRedisCacheManager(RedisOperations redisOperations) {
        super(redisOperations);
    } 

    @Override
    public Cache getCache(String name) {
        long expiredTime = defaultExpiration;
        if (name.contains(TTLSEPARATOR)) {
            String[] split = name.split(TTLSEPARATOR);
            String cacheName = split[0];
            try {
                expiredTime = Double.valueOf(split[1]).longValue();
            } catch (Exception e) {
                e.printStackTrace();
            }
            Cache cache = this.cacheMap.get(name);
            if (cache != null) {
                return cache;
            } else {
                synchronized (this.cacheMap) {
                    cache = this.cacheMap.get(name);
                    if (cache == null) {
                        cache = new RedisCache(cacheName, null, super.getRedisOperations(), expiredTime);
                        if (cache != null) {
                            cache = this.decorateCache(cache);
                            this.cacheMap.put(name, cache);
                        }
                    }

                    return cache;
                }
            }
        }
        return super.getCache(name);
    }
}
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CacheConfig;
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.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

@CacheConfig
@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport {

    @Bean
    public CacheManager cacheManager(RedisTemplate redisTemplate) {
        //设置序列化Key的实例化对象
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        //设置序列化Value的实例化对象
        ObjectMapper mapper = new ObjectMapper();
        mapper.findAndRegisterModules();
        mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
        GenericJackson2JsonRedisSerializer serializer = new GenericJackson2JsonRedisSerializer(mapper);
        redisTemplate.setValueSerializer(serializer);
        MyRedisCacheManager mrc = new MyRedisCacheManager(redisTemplate);
        return mrc;
    }
}

@Cacheable注解的属性使用

cacheNames和value

指定缓存组件的名字,通过下面代码可以看出可以将返回结果放在哪个缓存中,可以通过数组的方式指定多个缓存

 /**
  * Alias for {@link #cacheNames}.
  */
 @AliasFor("cacheNames")
 String[] value() default {};
 /**
  * Names of the caches in which method invocation results are stored.
  * <p>Names may be used to determine the target cache (or caches), matching
  * the qualifier value or bean name of a specific bean definition.
  * @since 4.2
  * @see #value
  * @see CacheConfig#cacheNames
  */
 @AliasFor("value")
 String[] cacheNames() default {};

key

缓存数据的时候使用的key,它是用来指定对应的缓存,模拟使用方法参数值作为key的值。也可以使用SpEL表达式的值来指定

 /**
  * Spring Expression Language (SpEL) expression for computing the key dynamically.
  * <p>Default is {@code ""}, meaning all method parameters are considered as a key,
  * unless a custom {@link #keyGenerator} has been configured.
  * <p>The SpEL expression evaluates against a dedicated context that provides the
  * following meta-data:
  * <ul>
  * <li>{@code #root.method}, {@code #root.target}, and {@code #root.caches} for
  * references to the {@link java.lang.reflect.Method method}, target object, and
  * affected cache(s) respectively.</li>
  * <li>Shortcuts for the method name ({@code #root.methodName}) and target class
  * ({@code #root.targetClass}) are also available.
  * <li>Method arguments can be accessed by index. For instance the second argument
  * can be accessed via {@code #root.args[1]}, {@code #p1} or {@code #a1}. Arguments
  * can also be accessed by name if that information is available.</li>
  * </ul>
  */
 String key() default "";
名称 位置 描述 示例
methodName root object 被调用的方法名称 #root.methodName
Method root object 被调用的方法 #root.method.name
Target root object 当前被调用的目标对象 #root.target
targetClass root object 当前被调用的目标对象类 #root.targetClass
args root object 被调用方法的参数列表#root.args[0]
caches root object 调用的缓存列表 #root.caches[0].name
argument name evaluation context 方法的参数名称可以直接使用#参数名 #p0,#a0等等
result evaluation context 执行方法后的返回值 #result

可以通过这个参数提示列表看看到这个key所支持的root object对象有哪些,通过这样的方式可以指定对应的key值。

keyGenerator

这个是表示指定的key的生成器,当然在之前分享中我们说过一个简单的key的生成策略。这里我们还可以通过自定的方式来实现这个key的生成策略。

keyGenerator

这个是表示指定的key的生成器,当然在之前分享中我们说过一个简单的key的生成策略。这里我们还可以通过自定的方式来实现这个key的生成策略。

import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.lang.reflect.Method;
import java.util.Arrays;
@Configuration
public class MyCacheConfig {
    @Bean("myKeyGenerator")
    public KeyGenerator keyGenerator(){
        return new KeyGenerator() {
            @Override
            public Object generate(Object target, Method method, Object... params) {
                return method.getName()+"["+ Arrays.asList(params).toString()+"]";
            }
        };
    }
}

在使用的时候可以通过一下的方式进行配置

@Cacheable(cacheNames = {"emp"},keyGenerator = "myKeyGenerator")
cacheManager指定缓存管理器
/**
  * The bean name of the custom {@link org.springframework.cache.CacheManager} to use to
  * create a default {@link org.springframework.cache.interceptor.CacheResolver} if none
  * is set already.
  * <p>Mutually exclusive with the {@link #cacheResolver}  attribute.
  * @see org.springframework.cache.interceptor.SimpleCacheResolver
  * @see CacheConfig#cacheManager
  */
 String cacheManager() default "";
 /**
  * The bean name of the custom {@link org.springframework.cache.interceptor.CacheResolver}
  * to use.
  * @see CacheConfig#cacheResolver
  */
 String cacheResolver() default "";

condition

指定复合条件的情况下才缓存。也可以通过SpEL表达式进行设置。这个配置规则和上面表格中的配置规则是相同的。

 /**
  * Spring Expression Language (SpEL) expression used for making the method
  * caching conditional.
  * <p>Default is {@code ""}, meaning the method result is always cached.
  * <p>The SpEL expression evaluates against a dedicated context that provides the
  * following meta-data:
  * <ul>
  * <li>{@code #root.method}, {@code #root.target}, and {@code #root.caches} for
  * references to the {@link java.lang.reflect.Method method}, target object, and
  * affected cache(s) respectively.</li>
  * <li>Shortcuts for the method name ({@code #root.methodName}) and target class
  * ({@code #root.targetClass}) are also available.
  * <li>Method arguments can be accessed by index. For instance the second argument
  * can be accessed via {@code #root.args[1]}, {@code #p1} or {@code #a1}. Arguments
  * can also be accessed by name if that information is available.</li>
  * </ul>
  */
 String condition() default "";

unless(除非)

当这个条件为true的时候,方法的返回值就不会被缓存。

/**
  * Spring Expression Language (SpEL) expression used to veto method caching.
  * <p>Unlike {@link #condition}, this expression is evaluated after the method
  * has been called and can therefore refer to the {@code result}.
  * <p>Default is {@code ""}, meaning that caching is never vetoed.
  * <p>The SpEL expression evaluates against a dedicated context that provides the
  * following meta-data:
  * <ul>
  * <li>{@code #result} for a reference to the result of the method invocation. For
  * supported wrappers such as {@code Optional}, {@code #result} refers to the actual
  * object, not the wrapper</li>
  * <li>{@code #root.method}, {@code #root.target}, and {@code #root.caches} for
  * references to the {@link java.lang.reflect.Method method}, target object, and
  * affected cache(s) respectively.</li>
  * <li>Shortcuts for the method name ({@code #root.methodName}) and target class
  * ({@code #root.targetClass}) are also available.
  * <li>Method arguments can be accessed by index. For instance the second argument
  * can be accessed via {@code #root.args[1]}, {@code #p1} or {@code #a1}. Arguments
  * can also be accessed by name if that information is available.</li>
  * </ul>
  * @since 3.2
  */
 String unless() default "";

sync

是否异步

/**
  * Synchronize the invocation of the underlying method if several threads are
  * attempting to load a value for the same key. The synchronization leads to
  * a couple of limitations:
  * <ol>
  * <li>{@link #unless()} is not supported</li>
  * <li>Only one cache may be specified</li>
  * <li>No other cache-related operation can be combined</li>
  * </ol>
  * This is effectively a hint and the actual cache provider that you are
  * using may not support it in a synchronized fashion. Check your provider
  * documentation for more details on the actual semantics.
  * @since 4.3
  * @see org.springframework.cache.Cache#get(Object, Callable)
  */
 boolean sync() default false;

注意

在使用这个属性的时候,当这个属性为true的时候,unless属性是不能使用的。

{@link #unless()} is not supported

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • Spring Boot 中使用cache缓存的方法

    一.什么是缓存 Cache Cache 一词最早来自于CPU设计 当CPU要读取一个数据时,首先从CPU缓存中查找,找到就立即读取并送给CPU处理:没有找到,就从速率相对较慢的内存中读取并送给CPU处理,同时把这个数据所在的数据块调入缓存中,可以使得以后对整块数据的读取都从缓存中进行,不必再调用内存.正是这样的读取机制使CPU读取缓存的命中率非常高(大多数CPU可达90%左右),也就是说CPU下一次要读取的数据90%都在CPU缓存中,只有大约10%需要从内存读取.这大大节省了CPU直接读取内存的

  • 详解SpringBoot2.0的@Cacheable(Redis)缓存失效时间解决方案

    问题   @Cacheable注解不支持配置过期时间,所有需要通过配置CacheManneg来配置默认的过期时间和针对每个类或者是方法进行缓存失效时间配置. 解决   可以采用如下的配置信息来解决的设置失效时间问题 配置信息 @Bean public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) { return new RedisCacheManager( RedisCacheWriter.no

  • springboot的缓存技术的实现

    引子 我门知道一个程序的瓶颈在于数据库,我门也知道内存的速度是大大快于硬盘的速度的.当我门需要重复的获取相同的数据的时候,我门一次又一次的请求数据库或者远程服务,导致大量的时间耗费在数据库查询或者远程方法的调用上,导致程序性能的恶化,这更是数据缓存要解决的问题. spring 缓存支持 spring定义了 org.springframework.cache.CacheManager和org.springframework.cache.Cache接口来统一不同的缓存技术.其中,CacheManag

  • spring boot+spring cache实现两级缓存(redis+caffeine)

    spring boot中集成了spring cache,并有多种缓存方式的实现,如:Redis.Caffeine.JCache.EhCache等等.但如果只用一种缓存,要么会有较大的网络消耗(如Redis),要么就是内存占用太大(如Caffeine这种应用内存缓存).在很多场景下,可以结合起来实现一.二级缓存的方式,能够很大程度提高应用的处理效率. 内容说明: 缓存.两级缓存 spring cache:主要包含spring cache定义的接口方法说明和注解中的属性说明 spring boot

  • springboot增加注解缓存@Cacheable的实现

    目录 springboot增加注解缓存@Cacheable 业务层使用 配置 @Cacheable注解的属性使用 cacheNames和value key keyGenerator keyGenerator condition unless(除非) sync springboot增加注解缓存@Cacheable 业务层使用 @Cacheable(value = "dictionary#1800", key = "#root.targetClass.simpleName +':

  • SpringBoot日志注解与缓存优化详解

    目录 日志注解: 缓存的优化: 总结 日志注解: 关于SpringBoot中的日志处理,在之前的文章中页写过: 点击进入 这次通过注解+Aop的方式来实现日志的输出: 首先需要定义一个注解类:  @Target(ElementType.METHOD)  @Retention(RetentionPolicy.RUNTIME)  @Documented  public @interface LogAnnotation {      String module() default "";  

  • SpringBoot使用Redis缓存的实现方法

    (1)pom.xml引入jar包,如下: <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> (2)修改项目启动类,增加注解@EnableCaching,开启缓存功能,如下: package springboot; import org

  • Springboot中使用缓存的示例代码

    在开发中,如果相同的查询条件去频繁查询数据库, 是不是会给数据库带来很大的压力呢? 因此,我们需要对查询出来的数据进行缓存,这样客户端只需要从数据库查询一次数据,然后会放入缓存中,以后再次查询时可以从缓存中读取. Spring3开始提供了强大的基于注解的缓存支持,可以通过注解配置方式低侵入的给原有Spring应用增加缓存功能,提高数据访问性能.  具体在Springboot中使用缓存如下: 1.在pom.xml中引入cache依赖,添加如下内容: <dependency> <groupI

  • 使用Springboot自定义注解,支持SPEL表达式

    目录 Springboot自定义注解,支持SPEL表达式 1.自定义注解 2.使用AOP拦截方法,解析注解参数 自定义注解结合切面和spel表达式 自定义一个注解 自定义一个service类,在需要拦截的方法上加上@Log注解 写一个自定义切面 pom文件的依赖 测试 增加内容 Springboot自定义注解,支持SPEL表达式 举例,自定义redis模糊删除注解 1.自定义注解 import java.lang.annotation.ElementType; import java.lang.

  • Springboot整合GuavaCache缓存过程解析

    这篇文章主要介绍了springboot整合GuavaCache缓存过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 Guava Cache是一种本地缓存机制,之所以叫本地缓存,是因为它不会把缓存数据放到外部文件或者其他服务器上,而是存放到了应用内存中. Guava Cache的优点是:简单.强大.轻量级. GuavaCache适用场景: 1.某些接口或者键值会被查询多次以上: 2.愿意使用或牺牲一些内存空间来提升访问或者计算速度: 3.缓

  • SpringBoot中默认缓存实现方案的示例代码

    在上一节中,我带大家学习了在Spring Boot中对缓存的实现方案,尤其是结合Spring Cache的注解的实现方案,接下来在本章节中,我带大家通过代码来实现. 一. Spring Boot实现默认缓存 1. 创建web项目 我们按照之前的经验,创建一个web程序,并将之改造成Spring Boot项目,具体过程略. 2. 添加依赖包 <dependency> <groupId>org.springframework.boot</groupId> <artif

  • SpringBoot集成cache缓存的实现

    前言 日常开发中,缓存是解决数据库压力的一种方案,通常用于频繁查询的数据,例如新闻中的热点新闻,本文记录springboot中使用cache缓存. 官方文档介绍:https://docs.spring.io/spring-boot/docs/2.1.0.RELEASE/reference/htmlsingle/#boot-features-caching-provider-generic 工程结构 代码编写 pom引入依赖,引入cache缓存,数据库使用mysql,ORM框架用jpa <!--添

  • SpringBoot 开启Redis缓存及使用方法

    目录 Redis缓存 主要步骤 具体实践 整体目录结构 yml文件里配置Redis集群 设置序列化的Bean 编写业务Controller 关于缓存的其他注解 检验结果 之前不是说过Redis可以当作缓存用嘛 现在我们就配置一下SpringBoot使用Redis的缓存 Redis缓存 为什么用Redis作缓存 用redis做缓存,是因为redis有着很优秀的读写能力,在集群下可以保证数据的高可用 主要步骤 1.pom.xml文件添加依赖 2.yml文件配置redis集群 3.编写RedisCon

  • SpringBoot使用Redis缓存MySql的方法步骤

    目录 1项目组成 2运行springboot 2.1官网download最基本的restful应用 2.2运行应用 3访问mysql 4设置redis缓存 1 项目组成 应用:springboot rest api 数据库:mysql jdbc框架:jpa 缓存中间件:redis 2 运行springboot 2.1 官网download最基本的restful应用 教程地址:https://spring.io/guides/gs/rest-service/ 直接download成品,找到git命

随机推荐