在srping cloud中,有个domain项目为数据字典,我现在的需求是,数据字典放在redis的15中,所以需要配置redis的多数据源。然后,在其他项目中,开启缓存,从redis15库中获取到所有数据。放到本地的缓存。所以缓存这一块考虑使用LocalCache。
首先:在domain项目中,实现redis的多数据源配置。然后在刷新缓存按钮触发时,把数据从DB存储到redis15库,在这个时候,需要去使用redis中的订阅发布来通知缓存去实时更新。
配置文件中加入自定义redis的配置
domainRedis:
host: 192.168.7.162
port: 30379
password:
# 连接超时时间(毫秒)
timeout: 10000
# 连接池中的最大空闲连接
max-idle: 8
# 连接池中的最小空闲连接
min-idle: 10
# 连接池最大连接数(使用负值表示没有限制)
max-active: 100
# 连接池最大阻塞等待时间(使用负值表示没有限制)
max-wait: -1
database: 15
RedisConfig.java 连接自定义redis
package com.bbg.domainManager.common.redis;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.bbg.domainManager.common.ConstantConfiguration;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.CacheManager;
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.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisPassword;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettucePoolingClientConfiguration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.listener.PatternTopic;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.data.redis.listener.adapter.MessageListenerAdapter;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import java.time.Duration;
/**
* redis配置类
*redisTemplate 默认jdk序列方式,用来保存对象等
* stringRedisTemplate 默认string的序列化方式,用于存储string格式
* @author zcc ON 2018/3/19
**/
@Configuration
@EnableCaching//开启注解
public class RedisConfig extends CachingConfigurerSupport {
@Primary
@Bean
public RedisConnectionFactory RedisConnectionFactory() {
/* ========= 基本配置 ========= */
RedisStandaloneConfiguration configuration = new RedisStandaloneConfiguration();
configuration.setHostName(hostName);
configuration.setPort(port);
configuration.setDatabase(database);
if (!ObjectUtils.isEmpty(password)) {
RedisPassword redisPassword = RedisPassword.of(password);
configuration.setPassword(redisPassword);
}
/* ========= 连接池通用配置 ========= */
GenericObjectPoolConfig genericObjectPoolConfig = new GenericObjectPoolConfig();
genericObjectPoolConfig.setMaxTotal(maxActive);
genericObjectPoolConfig.setMinIdle(minIdle);
genericObjectPoolConfig.setMaxIdle(maxIdle);
genericObjectPoolConfig.setMaxWaitMillis(maxWait);
LettucePoolingClientConfiguration.LettucePoolingClientConfigurationBuilder builder = LettucePoolingClientConfiguration.builder();
builder.poolConfig(genericObjectPoolConfig);
builder.commandTimeout(Duration.ofSeconds(timeout));
LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory(configuration, builder.build());
return connectionFactory;
}
/**
* 数据源2 redis template
*/
@Bean(name = "domainRedis")
public RedisTemplate redisTemplate(RedisConnectionFactory connectionFactory) {
//
// /* ========= 基本配置 ========= */
// RedisStandaloneConfiguration configuration = new RedisStandaloneConfiguration();
// configuration.setHostName(hostName);
// configuration.setPort(port);
// configuration.setDatabase(database);
// if (!ObjectUtils.isEmpty(password)) {
// RedisPassword redisPassword = RedisPassword.of(password);
// configuration.setPassword(redisPassword);
// }
//
// /* ========= 连接池通用配置 ========= */
// GenericObjectPoolConfig genericObjectPoolConfig = new GenericObjectPoolConfig();
// genericObjectPoolConfig.setMaxTotal(maxActive);
// genericObjectPoolConfig.setMinIdle(minIdle);
// genericObjectPoolConfig.setMaxIdle(maxIdle);
// genericObjectPoolConfig.setMaxWaitMillis(maxWait);
//
// /* ========= jedis pool ========= */
// /*
// JedisClientConfiguration.DefaultJedisClientConfigurationBuilder builder = (JedisClientConfiguration.DefaultJedisClientConfigurationBuilder) JedisClientConfiguration
// .builder();
// builder.connectTimeout(Duration.ofSeconds(timeout));
// builder.usePooling();
// builder.poolConfig(genericObjectPoolConfig);
// JedisConnectionFactory connectionFactory = new JedisConnectionFactory(configuration, builder.build());
// // 连接池初始化
// connectionFactory.afterPropertiesSet();
// */
//
// /* ========= lettuce pool ========= */
// LettucePoolingClientConfiguration.LettucePoolingClientConfigurationBuilder builder = LettucePoolingClientConfiguration.builder();
// builder.poolConfig(genericObjectPoolConfig);
// builder.commandTimeout(Duration.ofSeconds(timeout));
// LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory(configuration, builder.build());
// connectionFactory.afterPropertiesSet();
/* ========= 创建 template ========= */
return createRedisTemplate(connectionFactory);
}
/**
* json 实现 redisTemplate
* <p>
* 该方法不能加 @Bean 否则不管如何调用,connectionFactory都会是默认配置
*
* @param redisConnectionFactory
* @return
*/
public RedisTemplate createRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory);
// Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
//调用自己写的StringJackson2JsonSerializer来序列化,value中存储的是json
StringJackson2JsonSerializer<Object> jackson2JsonRedisSerializer = new StringJackson2JsonSerializer<Object>(Object.class);
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
RedisSerializer stringSerializer = new StringRedisSerializer();
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.setKeySerializer(stringSerializer);
redisTemplate.setHashKeySerializer(stringSerializer);
redisTemplate.setHashValueSerializer(stringSerializer);
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
/*
Redis 连接池: Lettuce、Jedis 比较
Jedis:
Jedis在实现上是直接连接的redis server,如果在多线程环境下是非线程安全的,这个时候只有使用连接池,为每个Jedis实例增加物理连接
Lettuce:
Lettuce的连接是基于Netty的,连接实例(StatefulRedisConnection)可以在多个线程间并发访问,应为StatefulRedisConnection是线程安全的,所以一个连接实例(StatefulRedisConnection)就可以满足多线程环境下的并发访问,当然这个也是可伸缩的设计,一个连接实例不够的情况也可以按需增加连接实例。
lettuce主要利用netty实现与redis的同步和异步通信。
*/
@Bean
public CacheManager cacheManager(RedisConnectionFactory factory) {
RedisCacheManager cacheManager = RedisCacheManager.create(factory);
return cacheManager;
}
// 以下两种redisTemplate自由根据场景选择
// @Bean
// public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
// RedisTemplate<Object, Object> template = new RedisTemplate<>();
// template.setConnectionFactory(connectionFactory);
//
// //使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值(默认使用JDK的序列化方式)
// Jackson2JsonRedisSerializer serializer = new Jackson2JsonRedisSerializer(Object.class);
//
// ObjectMapper mapper = new ObjectMapper();
// mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
// mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
// serializer.setObjectMapper(mapper);
//
// template.setValueSerializer(serializer);
// //使用StringRedisSerializer来序列化和反序列化redis的key值
// template.setHashKeySerializer(serializer);
// template.setHashValueSerializer(serializer);
// template.setKeySerializer(new StringRedisSerializer());
// template.afterPropertiesSet();
// return template;
// }
@Bean
public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory factory) {
StringRedisTemplate stringRedisTemplate = new StringRedisTemplate();
stringRedisTemplate.setConnectionFactory(factory);
return stringRedisTemplate;
}
/**
* redis消息监听器容器
* 可以添加多个监听不同话题的redis监听器,只需要把消息监听器和相应的消息订阅处理器绑定,该消息监听器
* 通过反射技术调用消息订阅处理器的相关方法进行一些业务处理
*
* @param connectionFactory
* @param listenerColumnDictAdapter
* @param listenerSysCconfigAdapter
* @return
*/
@Bean
RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory,
MessageListenerAdapter listenerColumnDictAdapter,
MessageListenerAdapter listenerSysCconfigAdapter) {
RedisMessageListenerContainer container = new RedisMessageListenerContainer();
container.setConnectionFactory(connectionFactory);
// 订阅通道指标映射字典
container.addMessageListener(listenerColumnDictAdapter, new PatternTopic(ConstantConfiguration.TOPIC_USERNAME));
// 订阅系统配置频道
container.addMessageListener(listenerSysCconfigAdapter, new PatternTopic(ConstantConfiguration.TOPIC_USERNAME));
return container;
}
/**
* 消息监听器适配器,绑定消息处理器,利用反射技术调用消息处理器的业务方法
*
* @param redisMessageReceiver
* @return
*/
@Bean
MessageListenerAdapter listenerColumnDictAdapter(RedisMessageReceiver redisMessageReceiver) {
return new MessageListenerAdapter(redisMessageReceiver, "receiveColumnDictMessage");
}
@Bean
MessageListenerAdapter listenerSysCconfigAdapter(RedisMessageReceiver redisMessageReceiver) {
return new MessageListenerAdapter(redisMessageReceiver, "receiveSysConfigMessage");
}
@Bean
StringRedisTemplate template(RedisConnectionFactory connectionFactory) {
return new StringRedisTemplate(connectionFactory);
}
}
RedisUtils.java redis的操作工具类
package com.bbg.domainManager.common.redis; /**
* @Title: ${file_name}
* @Package ${package_name}
* @Description: ${todo}
* @author xwq
* @date 2019/7/15 001516:58
*/
import org.springframework.data.redis.core.*;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.io.Serializable;
import java.util.HashMap;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
@Component
public class RedisUtils {
// @Autowired
// private RedisTemplate redisTemplate;
@Resource(name = "domainRedis")
private RedisTemplate redisTemplate;
public RedisUtils(RedisTemplate redisTemplate) {
this.redisTemplate = redisTemplate;
}
/**
* 写入缓存
* @param key
* @param value
* @return
*/
public boolean set(final String key, Object value) {
boolean result = false;
try {
ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
operations.set(key, value);
result = true;
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
/**
* 写入缓存设置时效时间
* @param key
* @param value
* @return
*/
public boolean set(final String key, Object value, Long expireTime) {
boolean result = false;
try {
ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
operations.set(key, value);
redisTemplate.expire(key, expireTime, TimeUnit.SECONDS);
result = true;
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
/**
* 批量删除对应的value
* @param keys
*/
public void remove(final String... keys) {
for (String key : keys) {
remove(key);
}
}
/**
* 批量删除key
* @param pattern
*/
public void removePattern(final String pattern) {
Set<Serializable> keys = redisTemplate.keys(pattern+"*");
if (keys.size() > 0)
redisTemplate.delete(keys);
}
/**
* 删除对应的value
* @param key
*/
public void remove(final String key) {
if (exists(key)) {
redisTemplate.delete(key);
}
}
/**
* 判断缓存中是否有对应的value
* @param key
* @return
*/
public boolean exists(final String key) {
return redisTemplate.hasKey(key);
}
/**
* 读取缓存
* @param key
* @return
*/
public Object get(final String key) {
Object result = null;
ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
result = operations.get(key);
return result;
}
/**
* 获取domain对象
*/
public static DomainDto getDomain(String key) throws IOException, ClassNotFoundException {
DomainDto domainDto = null;
domainDto = map != null && map.get(key) !=null ? (DomainDto)map.get(key) : domainDto ;
return domainDto == null ? domainDto : (DomainDto)CopyUtils.deepClone(domainDto);//获取缓存之后,进行深度复制,防止修改
// return (DomainDto)CopyUtils.deepClone(map.get("sys_domain:"+key));//获取缓存之后,进行深度复制,防止修改
}
/**
* 获取对应域值
* key:域key
* defineKey: 值key
*/
public static DomainDefineDto getDomainDefine(String key,String defineKey ) throws IOException, ClassNotFoundException {
DomainDto dto = getDomain(key);
DomainDefineDto defineDto = null;
if(dto != null ){
defineDto = dto.getMap().get(defineKey);
}
return defineDto;
}
/**
* 获取对应二级域值集合
* key:域key
* groupdmdkey: 二级分组值key
*/
public static List<DomainDefineDto> getDomainDefineCollection(String key, String groupdmdkey ) throws IOException, ClassNotFoundException {
DomainDto dto = getDomain(key);
DomainDefineDto defineDto = null;
if(dto != null ){
defineDto = dto.getMap().get(groupdmdkey);
}
return defineDto.getGroupdmdList();
}
/**
* 获取对应域动作
* key:域key
* transitionKey: 动作key
*/
public static DomainTransitionDto getDomainTransition(String key, String transitionKey ) throws IOException, ClassNotFoundException {
DomainDto dto = getDomain(key);
DomainTransitionDto domainTransitionDto = null;
if(dto != null ){
domainTransitionDto = dto.getTrMap().get(transitionKey);
}
return domainTransitionDto;
}
/**
* 哈希 添加
* @param key
* @param hashKey
* @param value
*/
public void hmSet(String key, Object hashKey, Object value){
HashOperations<String, Object, Object> hash = redisTemplate.opsForHash();
hash.put(key,hashKey,value);
}
/**
* 哈希获取数据
* @param key
* @param hashKey
* @return
*/
public Object hmGet(String key, Object hashKey){
HashOperations<String, Object, Object> hash = redisTemplate.opsForHash();
return hash.get(key,hashKey);
}
/**
* 列表添加
* @param k
* @param v
*/
public void lPush(String k,Object v){
ListOperations<String, Object> list = redisTemplate.opsForList();
list.rightPush(k,v);
}
/**
* 列表获取
* @param k
* @param l
* @param l1
* @return
*/
public List<Object> lRange(String k, long l, long l1){
ListOperations<String, Object> list = redisTemplate.opsForList();
return list.range(k,l,l1);
}
/**
* 集合添加
* @param key
* @param value
*/
public void add(String key,Object value){
SetOperations<String, Object> set = redisTemplate.opsForSet();
set.add(key,value);
}
/**
* 集合获取
* @param key
* @return
*/
public Set<Object> setMembers(String key){
SetOperations<String, Object> set = redisTemplate.opsForSet();
return set.members(key);
}
/**
* 有序集合添加
* @param key
* @param value
* @param scoure
*/
public void zAdd(String key,Object value,double scoure){
ZSetOperations<String, Object> zset = redisTemplate.opsForZSet();
zset.add(key,value,scoure);
}
/**
* 有序集合获取
* @param key
* @param scoure
* @param scoure1
* @return
*/
public Set<Object> rangeByScore(String key,double scoure,double scoure1){
ZSetOperations<String, Object> zset = redisTemplate.opsForZSet();
return zset.rangeByScore(key, scoure, scoure1);
}
/**
* 获取所有的key-value
*/
public HashMap<Object,Object> getAll(){
//获取所有的key
Set<String> keys = redisTemplate.keys("*");
//创建集合
HashMap<Object,Object> map = new HashMap<>();
//循环
Object result ;
for(String key : keys){
result = null;
ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
result = operations.get(key);
map.put(key,result);
}
return map;
}
}
RedisMessageReceiver.java 处理订阅消息的类这个时候其实自己是发布者,不需要实现订阅的逻辑
package com.bbg.domainManager.common.redis; /**
* @Title: ${file_name}
* @Package ${package_name}
* @Description: ${todo}
* @author xwq
* @date 2019/11/22 002214:22
*/
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
/**
* 处理订阅消息的类
* @author xwq
* @create 2019-11-22 14:22
**/
@Component
public class RedisMessageReceiver {
private static Logger logger = LoggerFactory.getLogger(RedisMessageReceiver.class);
/**
* 接受消息后,执行的方法
* @param message
*/
public void receiveColumnDictMessage(String message) {
logger.info("redis订阅者接受消息:{},更新全局变量缓存dict_column", message);
// ApplicationStartedInitializer bean = BeanUtil.getBean(ApplicationStartedInitializer.class);
// bean.initColumnDict();
}
/**
* redis 系统配置监听器
* @param message
*/
public void receiveSysConfigMessage(String message) {
logger.info("redis订阅者接受消息:{},更新全局变量缓存sysConfig", message);
// ApplicationStartedInitializer bean = BeanUtil.getBean(ApplicationStartedInitializer.class);
// bean.initSysConfig();
}
}
StringJackson2JsonSerializer.java 自定义的序列化,redis中value存储的值序列化为json
package com.bbg.domainManager.common.redis; /**
* @Title: ${file_name}
* @Package ${package_name}
* @Description: ${todo}
* @author xwq
* @date 2019/11/13 001310:28
*/
import com.alibaba.fastjson.JSON;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.SerializationException;
/**
*
* @author xwq
* @create 2019-11-13 10:28
**/
public class StringJackson2JsonSerializer<T> extends Jackson2JsonRedisSerializer<T> {
private ObjectMapper objectMapper = new ObjectMapper();
public StringJackson2JsonSerializer(Class<T> type) {
super(type);
// TODO Auto-generated constructor stub
}
public byte[] serialize(Object t) throws SerializationException {
if (t == null) {
return new byte[0];
}
try {
//将对象转为Json String然后再序列化,方便跨服务 JSON.toJSONString(
return this.objectMapper.writeValueAsBytes(JSON.toJSONString(t));
// return this.objectMapper.writeValueAsBytes(JacksonUtil.objToJson(t));
} catch (Exception ex) {
throw new SerializationException("Could not write JSON: " + ex.getMessage(), ex);
}
}
}
ConstantConfiguration。java 自定义枚举
package com.cloud.common.domain;
/**
* @ClassName ConstantConfiguration
* @Description TODO
* @Author wang
* @Date 2019/7/26 16:30
* @Version 1.0.1
**/
public class ConstantConfiguration {
public static final String MYSQL = "com.mysql.jdbc.Driver";
public static final String ORACLE = "oracle.jdbc.driver.OracleDriver";
public static final String TOPIC_USERNAME = "TOPIC_USERNAME";
public static final String DOMAIN = "DOMAIN";
public static final String DOMAIN_DEFINE = "DOMAIN_DEFINE";
public static final String DOMAIN_TRANSITION = "DOMAIN_TRANSITION";
}
页面中的刷新缓存按钮方法
defineDto1 = new DomainDefineDto();
defineDto1.setStatus(DomainStatusEnum.EFFECTIVITY.getCode());
defineDto1.setDomainKey(father.getKey());
fatherList = domainDefineDao.findForList(defineDto1);
}
for(DomainDefineDto dto1 : listDomainDefine){
//根据域值的key,去查询出对应的动作
// DomainTransitionDto transitionDto = new DomainTransitionDto();
// transitionDto.setStatus(DomainStatusEnum.EFFECTIVITY.getCode());
// transitionDto.setSrcstatekey(dto1.getKey());
// transitionDto.setDomainKey(dto.getKey());
// List<DomainTransitionDto> listDomainTransition = domainTransitionDao.findForList(transitionDto);
List<DomainTransitionDto> dtList = dtdMap.get(dto.getKey());
//再挑选出起点为dto1.getKey(),的动作
if(dtList != null){
List<DomainTransitionDto> listDomainTransition = dtList.stream()
.filter((DomainTransitionDto dt) -> dtList.contains(dto1.getKey().equals(dt.getSrcstatekey()) ))
.collect(Collectors.toList());
for(DomainTransitionDto dtDto : listDomainTransition){
//去获取到起始点的名称
if(StringUtils.isNotBlank(mapDefine.get(dtDto.getSrcstatekey()) )) {
dtDto.setSrcstatekeyName(mapDefine.get(dtDto.getSrcstatekey()));
}
//去获取到终点的名称
if(StringUtils.isNotBlank(mapDefine.get(dtDto.getTgtstatekey()) )) {
dtDto.setTgtstatekeyName(mapDefine.get(dtDto.getTgtstatekey()));
}
dto1.setTransitionList(listDomainTransition);
}
}
//因为在域值中有个二级分组,这里需要处理
if(fatherList.size()>0){
List<DomainDefineDto> list2 = new ArrayList<>();
for(DomainDefineDto fatherDto :fatherList){
if(dto1.getKey().equals(fatherDto.getGroupdmdkey())){
fatherDto.setGroupdmdkeyName(dto1.getName());
list2.add(fatherDto);
}
}
dto1.setGroupdmdList(list2);
hashMap.put(dto1.getKey(),dto1);
}
// if(!StringUtils.isNotBlank(dto1.getGroupdmdkey())){
// //说明二级分组字段为空,那就是第一级
// List<DomainDefineDto> list2 = new ArrayList<>();
// for(DomainDefineDto dto2 : listDomainDefine){
// if(dto1.getKey().equals(dto2.getGroupdmdkey())){
// dto2.setGroupdmdkeyName(mapDefine.get(dto2.getGroupdmdkey()));
//
// list2.add(dto2);
// }
// }
//
// dto1.setGroupdmdList(list2);
//
// hashMap.put(dto1.getKey(),dto1);
// }
}
dto.setMap((HashMap<String, DomainDefineDto>) hashMap);
//去查询域定义的所有的动作
// DomainTransitionDto t = new DomainTransitionDto();
// t.setStatus(DomainStatusEnum.EFFECTIVITY.getCode());
// t.setDomainKey(dto.getKey());
// List<DomainTransitionDto> transitionDtoList1= domainTransitionDao.findForList(t);
List<DomainTransitionDto> transitionDtoList1 = dtdMap.get(dto.getKey()) != null ? dtdMap.get(dto.getKey()) : new ArrayList<>();
Map<String, DomainTransitionDto> dtMap = new HashMap();
for(DomainTransitionDto dt : transitionDtoList1){
//去获取到起始点的名称
if(StringUtils.isNotBlank(mapDefine.get(dt.getSrcstatekey()) )) {
dt.setSrcstatekeyName(mapDefine.get(dt.getSrcstatekey()));
}
//去获取到终点的名称
if(StringUtils.isNotBlank(mapDefine.get(dt.getTgtstatekey()) )) {
dt.setTgtstatekeyName(mapDefine.get(dt.getTgtstatekey()));
}
dtMap.put(dt.getActionkeyname(),dt);
}
dto.setTrMap((HashMap<String, DomainTransitionDto>) dtMap);
mapdomain.put(dto.getKey(), dto);
}
//删除以前的缓存
redisUtils.set("sys_domain_map",mapdomain);
//在更新缓存之后,需要去通知
stringRedisTemplate.convertAndSend(ConstantConfiguration.TOPIC_USERNAME, "update column dict action");
}
stringRedisTemplate.convertAndSend(ConstantConfiguration.TOPIC_USERNAME, “update column dict action”);就是发布
到此时,redis的数据和数据库中已经同步了。接下来就是使用LocalCache来做本地缓存。之所以没有用redis的缓存自己去想。
先说放在cloud-common公共项目中的代码,cloud-common项目没有main方法,没有配置文件,直接就打包成jar到maven私库,供其他项目使用,其实就是把每个项目里面有的代码抽取出来.
cache包为LocalCache的本地缓存操作类
redis包为redis的操作类,基本和上面代码差不多,细微区别自己想要注意
cache中的LocalCache.java
package com.cloud.common.domain.cache; /**
* @Title: ${file_name}
* @Package ${package_name}
* @Description: ${todo}
* @author xwq
* @date 2019/11/25 002510:46
*/
import org.springframework.stereotype.Component;
import java.io.Serializable;
import java.util.Map;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
* 很多场景下,有些请求的数据,是不会经常改变的,这种时候,
* 为了减少数据库的查询压力,可以将这一部分数据放入缓存中,
* 直接从缓存中读取。除了一些像Redis等缓存外,还可以通过本地内存,作为缓存。
* 下边将使用ConcurrentHashMap来实现本地缓存。
*
*
ConcurrentHashMap --数据存储,线程安全的map
ScheduledExecutorService --线程定时调度服务
TimerTask --定时任务
lambda表达式
* @author xwq
* @create 2019-11-25 10:46
**/
@Component
public class LocalCache implements Serializable {
/**
* 1.用线程安全的ConcurrentHashMap来作为缓存数据的存储,
*2.然后通过定时调度任务TimerTask,来实现控制缓存的有效时间,根据缓存设置的
*超时时间,来定时清除对应的 key,实现缓存过期
*3.实现一些静态方法,来增加缓存、获取缓存等
*/
/**
* 1.多线程并行处理定时任务时,Timer运行多个TimeTask时,只要其中之一没有捕获
*抛出的异常其它任务便会自动终止运行,使用ScheduledExecutorService则没有这个问题
*2.Timer内部是一个线程,任务1所需的时间超过了两个任务间的间隔时会导致问题
*3.Timer执行周期任务时依赖系统时间
*/
private static final Map<String, Object> map;
private static final ScheduledExecutorService timerService; //定时器
/**
* 默认有效时长
*/
private static final long DEFAULT_TIMEOUT = 36;//默认过期时间
private static final long SECOND_TIME = 1000;//默认过期时间
/**
* 初始化块总是在构造器之前执行
* 静态初始化块执行的优先级高于非静态初始化块,在对象装载到JVM中时执行一次,仅能初始化类成员变量,即static修饰的数据成员
* 静态初始化块是类相关的,系统将在类加载时执行静态初始化块,而不是在创建对象时才执行,因此静态初始化块总是比非静态初始化块先执行
*/
static {
map = new LRUMap<>();
timerService = new ScheduledThreadPoolExecutor(1, new LocalCache.DaemonThreadFactory());
}
/**
* 工具类
*/
private LocalCache() {
}
static class LRUMap<K, V> extends ConcurrentHashMap<K, V> {
/**
* 默认缓存大小
*/
private static final int DEFAULT_INITIAL_CAPACITY = 1 << 4;
/**
* 默认最大缓存大小
*/
private static final int DEFAULT_MAX_CAPACITY = 1 << 30;
/**
* 默认加载因子
*/
private static final float DEFAULT_LOAD_FACTOR = 0.75f;
/**
* 读写锁
*/
private ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
private final Lock rLock = readWriteLock.readLock();
private final Lock wLock = readWriteLock.writeLock();
public LRUMap() {
super(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR);
}
public LRUMap(int initialCapacity) {
super(initialCapacity, DEFAULT_LOAD_FACTOR);
}
/**
* 需要重写LinkedHashMap中removeEldestEntry方法;
* 新增元素的时候,会判断当前map大小是否超过DEFAULT_MAX_CAPACITY,超过则移除map中最老的节点;
* @param eldest
* @return
*/
protected boolean removeEldestEntry(Entry<K,V> eldest) {
return size() > DEFAULT_MAX_CAPACITY;
}
public V put(K k, V v) {
wLock.lock();
try {
return super.put(k, v);
} finally {
wLock.unlock();
}
}
public V get(String k) {
rLock.lock();
try {
return super.get(k);
} finally {
rLock.unlock();
}
}
public void putAll(Map<? extends K, ? extends V> m) {
wLock.lock();
try {
super.putAll(m);
} finally {
wLock.unlock();
}
}
public V remove(Object k) {
wLock.lock();
try {
return super.remove(k);
} finally {
wLock.unlock();
}
}
public boolean containKey(K k) {
rLock.lock();
try {
return super.containsKey(k);
} finally {
rLock.unlock();
}
}
public int size() {
rLock.lock();
try {
return super.size();
} finally {
rLock.unlock();
}
}
public void clear() {
wLock.lock();
try {
super.clear();
} finally {
wLock.unlock();
}
}
}
/**
* 清除缓存的任务类
*/
static class CleanWorkerTask implements Runnable {
private String key;
public CleanWorkerTask(String key) {
this.key = key;
}
@Override
public void run() {
LocalCache.remove(key);
}
}
private static final class DaemonThreadFactory implements ThreadFactory {
private AtomicInteger atomicInteger = new AtomicInteger(0);
@Override
public Thread newThread(Runnable runnable) {
Thread thread = new Thread(runnable);
thread.setName("schedule-pool-Thread-" + atomicInteger.getAndIncrement());
thread.setDaemon(true);
return null;
}
}
/**
* 增加缓存
*/
public static void add(String key, Object value) {
map.put(key, value);
timerService.schedule(new CleanWorkerTask(key), DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS);
}
/**
* 增加缓存
* @param timeout 有效时长
*/
public static void add(String key, Object value, int timeout) {
map.put(key, value);
timerService.schedule(new CleanWorkerTask(key), timeout * SECOND_TIME, TimeUnit.MILLISECONDS);
}
public static void putAll(Map<String, Object> m, int timeout) {
map.putAll(m);
for (String key : m.keySet()) {
timerService.schedule(new CleanWorkerTask(key), timeout * SECOND_TIME, TimeUnit.MILLISECONDS);
}
}
public static void putAll(Map<String, Object> m) {
map.putAll(m);
for (String key : m.keySet()) {
timerService.schedule(new CleanWorkerTask(key), DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS);
}
}
/**
* 获取缓存
*/
public static Object get(String key) {
return map.get(key);
}
public static boolean containsKey(String key) {
return map.containsKey(key);
}
/**
*
* @param key
*/
public static void remove(String key) {
map.remove(key);
}
/**
*
* @param
*/
public static void clear() {
map.clear();
}
public static int size() {
return map.size();
}
}
MyStartupRunner.java
package com.cloud.common.domain.cache; /**
* @Title: ${file_name}
* @Package ${package_name}
* @Description: ${todo}
* @author xwq
* @date 2019/11/25 002515:59
*/
import com.cloud.common.domain.redis.RedisUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
import java.util.Map;
/**
*
SpringBoot项目启动时初始化缓存资源
Springboot中CommandLineRunner接口的
Component 会在所有 Spring Beans都初始化之后SpringApplication.run()之前执行
* @author xwq
* @create 2019-11-25 15:59
**/
@Component
public class MyStartupRunner implements CommandLineRunner {
@Autowired
private RedisUtils redisUtils;
@Override
public void run(String... args) throws Exception {
//清除所有缓存
LocalCache.clear();
// LocalCache.remove("*");
//获取到所有的redis数据
Map map = redisUtils.getAll();
// LocalCache.putAll(map,-1);//存储进去缓存
LocalCache.putAll(map);//存储进去缓存
}
}
ConstantConfiguration.java 枚举还是和上面的一样
package com.cloud.common.domain;
/**
* @ClassName ConstantConfiguration
* @Description TODO
* @Author wang
* @Date 2019/7/26 16:30
* @Version 1.0.1
**/
public class ConstantConfiguration {
public static final String MYSQL = "com.mysql.jdbc.Driver";
public static final String ORACLE = "oracle.jdbc.driver.OracleDriver";
public static final String TOPIC_USERNAME = "TOPIC_USERNAME";
public static final String DOMAIN = "DOMAIN";
public static final String DOMAIN_DEFINE = "DOMAIN_DEFINE";
public static final String DOMAIN_TRANSITION = "DOMAIN_TRANSITION";
}
redis包中的代码
RedisConfig.java
package com.cloud.common.domain.redis;
import com.cloud.common.domain.ConstantConfiguration;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.CacheManager;
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.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisPassword;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettucePoolingClientConfiguration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.listener.PatternTopic;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.data.redis.listener.adapter.MessageListenerAdapter;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.util.ObjectUtils;
import java.time.Duration;
/**
* redis配置类
*redisTemplate 默认jdk序列方式,用来保存对象等
* stringRedisTemplate 默认string的序列化方式,用于存储string格式
* @author zcc ON 2018/3/19
**/
@Configuration
@EnableCaching//开启注解
public class RedisConfig extends CachingConfigurerSupport {
/**
* 数据源2 redis template
*/
@Bean(name = "domainRedis")
public RedisTemplate redisTemplate(
@Value("${spring.domainRedis.database}") int database,
@Value("${spring.domainRedis.timeout}") long timeout,
@Value("${spring.domainRedis.max-active}") int maxActive,
@Value("${spring.domainRedis.max-wait}") int maxWait,
@Value("${spring.domainRedis.max-idle}") int maxIdle,
@Value("${spring.domainRedis.min-idle}") int minIdle,
@Value("${spring.domainRedis.host}") String hostName,
@Value("${spring.domainRedis.port}") int port,
@Value("${spring.domainRedis.password}") String password) {
/* ========= 基本配置 ========= */
RedisStandaloneConfiguration configuration = new RedisStandaloneConfiguration();
configuration.setHostName(hostName);
configuration.setPort(port);
configuration.setDatabase(database);
if (!ObjectUtils.isEmpty(password)) {
RedisPassword redisPassword = RedisPassword.of(password);
configuration.setPassword(redisPassword);
}
/* ========= 连接池通用配置 ========= */
GenericObjectPoolConfig genericObjectPoolConfig = new GenericObjectPoolConfig();
genericObjectPoolConfig.setMaxTotal(maxActive);
genericObjectPoolConfig.setMinIdle(minIdle);
genericObjectPoolConfig.setMaxIdle(maxIdle);
genericObjectPoolConfig.setMaxWaitMillis(maxWait);
/* ========= jedis pool ========= */
/*
JedisClientConfiguration.DefaultJedisClientConfigurationBuilder builder = (JedisClientConfiguration.DefaultJedisClientConfigurationBuilder) JedisClientConfiguration
.builder();
builder.connectTimeout(Duration.ofSeconds(timeout));
builder.usePooling();
builder.poolConfig(genericObjectPoolConfig);
JedisConnectionFactory connectionFactory = new JedisConnectionFactory(configuration, builder.build());
// 连接池初始化
connectionFactory.afterPropertiesSet();
*/
/* ========= lettuce pool ========= */
LettucePoolingClientConfiguration.LettucePoolingClientConfigurationBuilder builder = LettucePoolingClientConfiguration.builder();
builder.poolConfig(genericObjectPoolConfig);
builder.commandTimeout(Duration.ofSeconds(timeout));
LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory(configuration, builder.build());
connectionFactory.afterPropertiesSet();
/* ========= 创建 template ========= */
return createRedisTemplate(connectionFactory);
}
/**
* json 实现 redisTemplate
* <p>
* 该方法不能加 @Bean 否则不管如何调用,connectionFactory都会是默认配置
*
* @param redisConnectionFactory
* @return
*/
public RedisTemplate createRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory);
// Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
StringJackson2JsonSerializer<Object> jackson2JsonRedisSerializer = new StringJackson2JsonSerializer<Object>(Object.class);
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
/*
Redis 连接池: Lettuce、Jedis 比较
Jedis:
Jedis在实现上是直接连接的redis server,如果在多线程环境下是非线程安全的,这个时候只有使用连接池,为每个Jedis实例增加物理连接
Lettuce:
Lettuce的连接是基于Netty的,连接实例(StatefulRedisConnection)可以在多个线程间并发访问,应为StatefulRedisConnection是线程安全的,所以一个连接实例(StatefulRedisConnection)就可以满足多线程环境下的并发访问,当然这个也是可伸缩的设计,一个连接实例不够的情况也可以按需增加连接实例。
lettuce主要利用netty实现与redis的同步和异步通信。
*/
@Bean
public CacheManager cacheManager(RedisConnectionFactory factory) {
RedisCacheManager cacheManager = RedisCacheManager.create(factory);
return cacheManager;
}
// 以下两种redisTemplate自由根据场景选择
// @Bean
// public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
// RedisTemplate<Object, Object> template = new RedisTemplate<>();
// template.setConnectionFactory(connectionFactory);
//
// //使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值(默认使用JDK的序列化方式)
// Jackson2JsonRedisSerializer serializer = new Jackson2JsonRedisSerializer(Object.class);
//
//
// ObjectMapper mapper = new ObjectMapper();
// mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
// mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
// serializer.setObjectMapper(mapper);
//
// template.setValueSerializer(serializer);
// //使用StringRedisSerializer来序列化和反序列化redis的key值
// template.setHashKeySerializer(serializer);
// template.setHashValueSerializer(serializer);
// template.setKeySerializer(new StringRedisSerializer());
// template.afterPropertiesSet();
// return template;
// }
// @Primary//指定为首要的缓存
// @Bean("cacheManager")
// public CacheManager redisCacheManager(RedisTemplate redisTemplate) {
// RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofSeconds(60));
// RedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(redisTemplate.getConnectionFactory());
// return new RedisCacheManager(redisCacheWriter, redisCacheConfiguration);
// }
@Bean
public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory factory) {
StringRedisTemplate stringRedisTemplate = new StringRedisTemplate();
stringRedisTemplate.setConnectionFactory(factory);
return stringRedisTemplate;
}
/**
* redis消息监听器容器
* 可以添加多个监听不同话题的redis监听器,只需要把消息监听器和相应的消息订阅处理器绑定,该消息监听器
* 通过反射技术调用消息订阅处理器的相关方法进行一些业务处理
*
* @param connectionFactory
* @param listenerColumnDictAdapter
* @param listenerSysCconfigAdapter
* @return
*/
@Bean
RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory,
MessageListenerAdapter listenerColumnDictAdapter,
MessageListenerAdapter listenerSysCconfigAdapter) {
RedisMessageListenerContainer container = new RedisMessageListenerContainer();
container.setConnectionFactory(connectionFactory);
// 订阅通道指标映射字典
container.addMessageListener(listenerColumnDictAdapter, new PatternTopic(ConstantConfiguration.TOPIC_USERNAME));
// 订阅系统配置频道
container.addMessageListener(listenerSysCconfigAdapter, new PatternTopic(ConstantConfiguration.TOPIC_USERNAME));
return container;
}
/**
* 消息监听器适配器,绑定消息处理器,利用反射技术调用消息处理器的业务方法
*
* @param redisMessageReceiver
* @return
*/
@Bean
MessageListenerAdapter listenerColumnDictAdapter(RedisMessageReceiver redisMessageReceiver) {
return new MessageListenerAdapter(redisMessageReceiver, "receiveColumnDictMessage");
}
@Bean
MessageListenerAdapter listenerSysCconfigAdapter(RedisMessageReceiver redisMessageReceiver) {
return new MessageListenerAdapter(redisMessageReceiver, "receiveSysConfigMessage");
}
@Bean
StringRedisTemplate template(RedisConnectionFactory connectionFactory) {
return new StringRedisTemplate(connectionFactory);
}
}
RedisMessageReceiver.java
package com.cloud.common.domain.redis; /**
* @Title: ${file_name}
* @Package ${package_name}
* @Description: ${todo}
* @author xwq
* @date 2019/11/22 002214:22
*/
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.cloud.common.domain.cache.LocalCache;
import java.util.Map;
/**
* 处理订阅消息的类
* @author xwq
* @create 2019-11-22 14:22
**/
@Component
public class RedisMessageReceiver {
private static Logger logger = LoggerFactory.getLogger(RedisMessageReceiver.class);
@Autowired
private RedisUtils redisUtils;
/**
* 接受消息后,执行的方法
* @param message
*/
public void receiveColumnDictMessage(String message) {
logger.info("redis订阅者接受消息:{},更新全局变量缓存dict_column", message);
//清除所有缓存
LocalCache.clear();
// LocalCache.remove("*");
//获取到所有的redis数据
Map map = redisUtils.getAll();
LocalCache.putAll(map,-1);//存储进去缓存
}
/**
* redis 系统配置监听器
* @param message
*/
public void receiveSysConfigMessage(String message) {
logger.info("redis订阅者接受消息:{},系统配置监听器更新全局变量缓存sysConfig", message);
//清除所有缓存
LocalCache.clear();
// LocalCache.remove("*");
//获取到所有的redis数据
Map map = redisUtils.getAll();
LocalCache.putAll(map,-1);//存储进去缓存
}
}
RedisUtils.java
package com.cloud.common.domain.redis; /**
* @Title: ${file_name}
* @Package ${package_name}
* @Description: ${todo}
* @author xwq
* @date 2019/7/15 001516:58
*/
import org.springframework.data.redis.core.*;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.io.Serializable;
import java.util.HashMap;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
@Component
public class RedisUtils {
// @Autowired
// private RedisTemplate redisTemplate;
@Resource(name = "domainRedis")
private RedisTemplate redisTemplate;
public RedisUtils(RedisTemplate redisTemplate) {
this.redisTemplate = redisTemplate;
}
/**
* 写入缓存
* @param key
* @param value
* @return
*/
public boolean set(final String key, Object value) {
boolean result = false;
try {
ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
operations.set(key, value);
result = true;
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
/**
* 写入缓存设置时效时间
* @param key
* @param value
* @return
*/
public boolean set(final String key, Object value, Long expireTime) {
boolean result = false;
try {
ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
operations.set(key, value);
redisTemplate.expire(key, expireTime, TimeUnit.SECONDS);
result = true;
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
/**
* 批量删除对应的value
* @param keys
*/
public void remove(final String... keys) {
for (String key : keys) {
remove(key);
}
}
/**
* 批量删除key
* @param pattern
*/
public void removePattern(final String pattern) {
Set<Serializable> keys = redisTemplate.keys(pattern+"*");
if (keys.size() > 0)
redisTemplate.delete(keys);
}
/**
* 删除对应的value
* @param key
*/
public void remove(final String key) {
if (exists(key)) {
redisTemplate.delete(key);
}
}
/**
* 判断缓存中是否有对应的value
* @param key
* @return
*/
public boolean exists(final String key) {
return redisTemplate.hasKey(key);
}
/**
* 读取缓存
* @param key
* @return
*/
public Object get(final String key) {
Object result = null;
ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
result = operations.get(key);
return result;
}
/**
* 哈希 添加
* @param key
* @param hashKey
* @param value
*/
public void hmSet(String key, Object hashKey, Object value){
HashOperations<String, Object, Object> hash = redisTemplate.opsForHash();
hash.put(key,hashKey,value);
}
/**
* 哈希获取数据
* @param key
* @param hashKey
* @return
*/
public Object hmGet(String key, Object hashKey){
HashOperations<String, Object, Object> hash = redisTemplate.opsForHash();
return hash.get(key,hashKey);
}
/**
* 列表添加
* @param k
* @param v
*/
public void lPush(String k,Object v){
ListOperations<String, Object> list = redisTemplate.opsForList();
list.rightPush(k,v);
}
/**
* 列表获取
* @param k
* @param l
* @param l1
* @return
*/
public List<Object> lRange(String k, long l, long l1){
ListOperations<String, Object> list = redisTemplate.opsForList();
return list.range(k,l,l1);
}
/**
* 集合添加
* @param key
* @param value
*/
public void add(String key,Object value){
SetOperations<String, Object> set = redisTemplate.opsForSet();
set.add(key,value);
}
/**
* 集合获取
* @param key
* @return
*/
public Set<Object> setMembers(String key){
SetOperations<String, Object> set = redisTemplate.opsForSet();
return set.members(key);
}
/**
* 有序集合添加
* @param key
* @param value
* @param scoure
*/
public void zAdd(String key,Object value,double scoure){
ZSetOperations<String, Object> zset = redisTemplate.opsForZSet();
zset.add(key,value,scoure);
}
/**
* 有序集合获取
* @param key
* @param scoure
* @param scoure1
* @return
*/
public Set<Object> rangeByScore(String key,double scoure,double scoure1){
ZSetOperations<String, Object> zset = redisTemplate.opsForZSet();
return zset.rangeByScore(key, scoure, scoure1);
}
/**
* 获取所有的key-value
*/
public HashMap<Object,Object> getAll(){
//获取所有的key
Set<String> keys = redisTemplate.keys("*");
//创建集合
HashMap<Object,Object> map = new HashMap<>();
//循环
Object result ;
for(String key : keys){
result = null;
ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
result = operations.get(key);
map.put(key,result);
}
return map;
}
}
StringJackson2JsonSerializer.java
package com.cloud.common.domain.redis; /**
* @Title: ${file_name}
* @Package ${package_name}
* @Description: ${todo}
* @author xwq
* @date 2019/11/13 001310:28
*/
import com.alibaba.fastjson.JSON;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.SerializationException;
/**
*
* @author xwq
* @create 2019-11-13 10:28
**/
public class StringJackson2JsonSerializer<T> extends Jackson2JsonRedisSerializer<T> {
private ObjectMapper objectMapper = new ObjectMapper();
public StringJackson2JsonSerializer(Class<T> type) {
super(type);
// TODO Auto-generated constructor stub
}
public byte[] serialize(Object t) throws SerializationException {
if (t == null) {
return new byte[0];
}
try {
//将对象转为Json String然后再序列化,方便跨服务 JSON.toJSONString(
return this.objectMapper.writeValueAsBytes(JSON.toJSONString(t));
// return this.objectMapper.writeValueAsBytes(JacksonUtil.objToJson(t));
} catch (Exception ex) {
throw new SerializationException("Could not write JSON: " + ex.getMessage(), ex);
}
}
}
cloud-common项目中的代码就完成了,接下来打包成jar到maven私库。
然后我自己新建一个项目cloud-domain来测试代码。
首先在pom中引入jar
<dependency>
<groupId>com.bbg</groupId>
<artifactId>cloud-common</artifactId>
<version>0.0.1</version>
<scope>compile</scope>
</dependency>
在配置文件中一定要加入自定义redis的配置
domainRedis:
host: 192.168.7.162
port: 30379
password:
# 连接超时时间(毫秒)
timeout: 10000
# 连接池中的最大空闲连接
max-idle: 8
# 连接池中的最小空闲连接
min-idle: 10
# 连接池最大连接数(使用负值表示没有限制)
max-active: 100
# 连接池最大阻塞等待时间(使用负值表示没有限制)
max-wait: -1
database: 15
因为在jar包RedisConfig.java中有取参数,如果没有启动报错
然后在main方法中加入@EnableCaching开启缓存
使用
@RequestMapping(value="/getDomainKeyRedis", method = {RequestMethod.POST, RequestMethod.GET })
@ResponseBody
@ApiOperation(value="域管理根据域key查询redis",notes="根据参数域key,查询对应的数据,常用于下拉框")
public DomainDto getDomainKeyRedis(HttpServletRequest request) {
String key = request.getParameter("key");
DomainDto domainDto = new DomainDto();
if(StrUtil.isEmpty(key)){
return domainDto;
}
// redisUtils.get("sys_domain:"+key);
// domainDto = JSON.parseObject((byte[]) redisUtils.get("sys_domain:"+key),DomainDto.class);
// domainDto = JSONObject.toJavaObject(JSONObject.parseObject(String.valueOf(redisUtils.get("sys_domain:"+key))),DomainDto.class);
//根据缓存查询
Object obj= localCache.get("sys_domain:"+key);
if(obj != null){
domainDto = JSONObject.toJavaObject(JSONObject.parseObject(String.valueOf(obj)),DomainDto.class);
}
return domainDto;
}
接下来cloud-domain项目的流程说明
cloud-domain项目引用了cloud-common的jar包,为保证每次项目启动的时候去redis获取到所有数据存储到缓存。MyStartupRunner.java实现了这个功能。
其实第一句清楚所有缓存可以去掉。但是无所谓了
然后redis更新的时候,对应的cloud-domain项目中需要更新缓存。
RedisMessageReceiver.java
接收到消息,