阅读 239

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

这篇文章主要介绍了springboot增加注解缓存@Cacheable的实现,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

目录
  • springboot增加注解缓存@Cacheable

    • 业务层使用

    • 配置

  • @Cacheable注解的属性使用

    • cacheNames和value

    • key

    • keyGenerator

    • keyGenerator

    • condition

    • unless(除非)

    • sync

springboot增加注解缓存@Cacheable

业务层使用

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

配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
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);
    
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
 * 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表达式的值来指定

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
 * 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 "";
名称位置描述示例
methodNameroot object被调用的方法名称#root.methodName
Methodroot object被调用的方法#root.method.name
Targetroot object当前被调用的目标对象#root.target
targetClassroot object当前被调用的目标对象类#root.targetClass
argsroot object被调用方法的参数列表#root.args[0]
cachesroot object调用的缓存列表#root.caches[0].name
argument nameevaluation context方法的参数名称可以直接使用#参数名#p0,#a0等等
resultevaluation context执行方法后的返回值#result

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

在这里插入图片描述


keyGenerator

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

keyGenerator

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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()+"]";
            }
        };
    }
}

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

1
@Cacheable(cacheNames = {"emp"},keyGenerator = "myKeyGenerator")
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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表达式进行设置。这个配置规则和上面表格中的配置规则是相同的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
 * 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的时候,方法的返回值就不会被缓存。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/**
  * 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

是否异步

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
  * 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属性是不能使用的。

1
{@link #unless()} is not supported

以上为个人经验,希望能给大家一个参考

原文链接:https://yasugongshang.blog.csdn.net/article/details/81773325


文章分类
代码人生
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐