项目开发中,SpringCache是一个非常方便的工具,但是在配置信息注册时,用枚举方式可以满足遍历,但却无法应用在@Cacheable注解里,因此可以通过静态类的方式,借助反射完成缓存信息注册。

配置类如下:

package com.zora.cloud.demo.config;

import com.alibaba.fastjson.support.spring.GenericFastJsonRedisSerializer;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.StringRedisSerializer; import java.lang.reflect.Field;
import java.time.Duration;
import java.util.HashMap;
import java.util.Map; /**
* <h3>metaapp-gamex</h3>
* <h4>com.metaapp.cloud.gamex.config</h4>
* <p>SpringCache配置</p>
*
* @author Yuhan.Ji
* @since 2020.03.23
*/
@Slf4j
@Configuration
public class CacheConfig {
private String appName = "Demo";
/**
* 当没有配置缓存失效时间情况下的默认ttl
*/
public static final int DEFAULT_EXPIRE_SECOND = 180; // 用于SpringBoot 2.0和2.1的配置方式
@Bean
public RedisCacheManager builder(RedisConnectionFactory factory) {
try {
// 这里的参数填充对应的静态属性类
Map<String, Integer> configMap = ReflectUtil.getCacheTtlConfigMap(Constants.class);
RedisCacheManager.RedisCacheManagerBuilder builder = RedisCacheManager.RedisCacheManagerBuilder
.fromConnectionFactory(factory);
if (!configMap.isEmpty()) {
Map<String, RedisCacheConfiguration> configurationMap = new HashMap<>();
for (String cacheName : configMap.keySet()) {
configurationMap.
put(cacheName, RedisCacheConfiguration
.defaultCacheConfig()
.computePrefixWith(name -> appName + ":" + name + ":")
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericFastJsonRedisSerializer()))
.entryTtl(Duration.ofSeconds(configMap.get(cacheName))));
}
builder.withInitialCacheConfigurations(configurationMap);
log.info("MetaApp Spring Cache Redis : 缓存配置为:{}", configMap.toString());
}
return builder.build();
} catch (IllegalAccessException illegalEx) {
log.error("SpringCache RedisCacheManagerBuilderCustomizer配置失败,启动终止。请检查RedisCacheManagerBuilder类中ReflectUtil.getCacheTtlConfigMap()部分", illegalEx);
System.exit(500);
return null;
}
} // // 用于SpringBoot 2.2 的配置方式
// @Bean
// public RedisCacheManagerBuilderCustomizer redisCacheManagerBuilderCustomizer() {
// return builder -> {
// try {
// // 这里的参数填充对应的静态属性类
// Map<String, Integer> configMap = ReflectUtil.getCacheTtlConfigMap(Constants.class);
// if (!configMap.isEmpty()) {
// Map<String, RedisCacheConfiguration> configurationMap = new HashMap<>();
// for (String cacheName : configMap.keySet()) {
// configurationMap.
// put(cacheName, RedisCacheConfiguration
// .defaultCacheConfig()
// .computePrefixWith(name -> appName + ":" + name + ":")
// .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
// .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericFastJsonRedisSerializer()))
// .entryTtl(Duration.ofSeconds(configMap.get(cacheName))));
// }
// builder.withInitialCacheConfigurations(configurationMap);
// log.info("Redis缓存配置为:{}",configMap.toString());
// }
// } catch (IllegalAccessException illegalEx) {
// log.error("SpringCache RedisCacheManagerBuilderCustomizer配置失败,启动终止。请检查RedisCacheManagerBuilder类中ReflectUtil.getCacheTtlConfigMap()部分", illegalEx);
// System.exit(500);
// }
// };
// } static class ReflectUtil {
public static final String CACHE_NAME_PREFIX = "CACHE_NAME_";
public static final String CACHE_TTL_PREFIX = "CACHE_TTL_"; static <T> Map<String, Integer> getCacheTtlConfigMap(Class<T> clazz) throws IllegalAccessException {
Map<String, Integer> cacheMapWithKeyTtl = new HashMap<>();
Field[] fields = clazz.getFields();
Map<String, String> cacheNames = new HashMap<>(fields.length);
// 配置cacheName
for (Field field : fields) {
if (field.getName().contains(CACHE_NAME_PREFIX)) {
if (field.getType().equals(String.class)) {
String lookingForTtlName = field.getName().replace(CACHE_NAME_PREFIX, CACHE_TTL_PREFIX);
String value = (String) field.get(clazz);
cacheNames.put(lookingForTtlName, value);
} else {
throw new IllegalAccessException("In constants configuration, the type of prefix of cache must be String. Illegal in " + clazz.getName() + "." + field.getName() + ".");
}
}
}
// 配置过期时间
for (Field field : fields) {
if (field.getName().contains(CACHE_TTL_PREFIX)) {
if (field.getType().equals(int.class) || field.getType().equals(Integer.class)) {
if (cacheNames.containsKey(field.getName())) {
cacheMapWithKeyTtl.put(cacheNames.get(field.getName()), field.getInt(clazz));
}
} else {
throw new IllegalAccessException("In constants configuration, the type of prefix of ttl must be int or Integer. Illegal in " + clazz.getName() + "." + field.getName() + ".");
}
}
}
// 配置默认过期时间
for (String cacheNameKey : cacheNames.keySet()) {
String cacheName = cacheNames.get(cacheNameKey);
if (!cacheMapWithKeyTtl.containsKey(cacheNames.get(cacheNameKey))) {
log.warn("===========================Spring Cache Config 配置信息错误=========================");
log.warn("Spring Cache Config 配置信息错误:{}文件中的缓存{}没有查询到对应失效时间的配置信息,将按默认值180秒执行。", clazz.getName(), cacheName);
log.warn("=============================== Zora Cache Config ================================");
cacheMapWithKeyTtl.put(cacheName, DEFAULT_EXPIRE_SECOND);
}
}
return cacheMapWithKeyTtl;
}
}
}

利用反射注册SpringCache的RedisCacheManager缓存信息的更多相关文章

  1. java封装返回结果应用 利用反射机制 返回结果以及错误信息

    //此方法是自己琢磨的,可能有漏洞--符合我的系统目前的需求,大家可以借鉴public ResponseMessage exec (String funname, Object[] params,Ob ...

  2. 利用反射来实现获取成员的指定特性(Attribute)信息

    在开发过程中,我们经常需要自定义一些特性,来辅助我们完成对对象或者枚举进行管理.我们需要知道如何获取对象使用的特性信息. 以下举个学习用的例子. 我们自定义一个特性类,这个特性设置在一个数据段内是否执 ...

  3. c#反射机制学习和利用反射获取类型信息

    反射(Reflection)是.NET中的重要机制,通过放射,可以在运行时获得.NET中每一个类型(包括类.结构.委托.接口和枚举等)的成员,包括方法.属性.事件,以及构造函数等.还可以获得每个成员的 ...

  4. C# winform利用反射和自定义特性加载功能模块(插件式开发)

    由于在实际的工作中, 碰见这样的一个问题: 一个软件, 销售给A客户 他需要所有功能, 但是销售给B客户, 他只需要其中的一部分, 1.如果我们在实际的开发过程中, 没有把一些功能模块区分开来的话, ...

  5. 利用反射快速给Model实体赋值 使用 Task 简化异步编程 Guid ToString 格式知多少?(GUID 格式) Parallel Programming-实现并行操作的流水线(生产者、消费者) c# 无损高质量压缩图片代码 8种主要排序算法的C#实现 (一) 8种主要排序算法的C#实现 (二)

    试想这样一个业务需求:有一张合同表,由于合同涉及内容比较多所以此表比较庞大,大概有120多个字段.现在合同每一次变更时都需要对合同原始信息进行归档一次,版本号依次递增.那么我们就要新建一张合同历史表, ...

  6. 【转】利用反射快速给Model实体赋值

    原文地址:http://blog.csdn.net/gxiangzi/article/details/8629064 试想这样一个业务需求:有一张合同表,由于合同涉及内容比较多所以此表比较庞大,大概有 ...

  7. 静态代理和利用反射形成的动态代理(JDK动态代理)

    代理模式 代理模式的定义:为其他对象提供一种代理以控制对这个对象的访问.在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用. 静态代理 1.新建 ...

  8. 利用反射实现通用的excel导入导出

    如果一个项目中存在多种信息的导入导出,为了简化代码,就需要用反射实现通用的excel导入导出 实例代码如下: 1.创建一个 Book类,并编写set和get方法 package com.bean; p ...

  9. [.net 面向对象程序设计进阶] (21) 反射(Reflection)(下)设计模式中利用反射解耦

    [.net 面向对象程序设计进阶] (21) 反射(Reflection)(下)设计模式中利用反射解耦 本节导读:上篇文章简单介绍了.NET面向对象中一个重要的技术反射的基本应用,它可以让我们动态的调 ...

随机推荐

  1. Java swing实现酒店管理系统

    今天给大家提供一个由今天给大家提供一个由Java swing实现的酒店管理系统,数据库采用sqlserver,我会贴上部分代码,完整的代码请看文章最下方下载,下面看代码: 1.主框架代码: packa ...

  2. jQuery JSONP

    同源策略 浏览器不允许跨域发送Ajax请求,如你在http://127.0.0.1:8000/下发送一个Ajax请求去获取http://127.0.0.1:9000/的资源. 如何解决这个问题?其实j ...

  3. python风格代码荟萃

    今天总结一下在python中常用的一些风格代码,这些可能大家都会用,但有时可能也会忘记,在这里总结,工大家参考~~~ 先点赞在看,养成习惯~~~ 标题遍历一个范围内的数字 for i in xrang ...

  4. 服务器断电导致的ORACLE异常 : ORA-00214 ORA-01033 ORA-01034 ORA-00172 ORA-27101

    工作环境中的集群迁移之后,oracle出了挺多问题,最开始一直没找到原因,后来发现做迁移的人是冷迁移的,且数据库节点是硬关机的,惊了( 表现症状有不能登陆,登录了不能操作等 第一个报的是 ORA-00 ...

  5. 第一次本地代码提交到github

    1.在个github上创建一个库 2.创建成功后,可以看到自己的仓库地址 3.在本地新建一个文件夹,并通过个git clone将仓库克隆到本地,并进入文件夹下 4.将需要提交的代码放入文件下,然后在终 ...

  6. hibernate3.6-联合主键注解以及openSession和getCurrentSession区别

    [联合主键]>>>>配置方式:xml:    1. Student中单独创建StudentPk主键实体类 2. 配置: <composite-id name=" ...

  7. c++与c

    const char* c_str ( ) const; Get C string equivalent Generates a null-terminated sequence of charact ...

  8. gdb调试core dump使用

    什么是coredump? Coredump叫做核心转储,它是进程运行时在突然崩溃的那一刻的一个内存快照.操作系统在程序发生异常而异常在进程内部又没有被捕获的情况下,会把进程此刻内存.寄存器状态.运行堆 ...

  9. JS 实现飞机大战

    这是JS版本的飞机大战,和C#版本的思路相同,就是语言上有差别,用来巩固知识.可以将代码直接引入到HTML中就可以看到效果 //编写背景对象 function Background(width,hei ...

  10. Serilog 源码解析——数据的保存(下)

    上一篇中,我们提到了日志数据是如何进行解析了.然而,Serilog 灵活采用了不同的策略(Policy)决定一个日志对象如何解析到LogEventPropertyValue的子类对象中,即采用了ISc ...