spring cloud中redis多数据源的使用和LocalCache本地缓存的使用

在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
接收到消息,

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用SpringCacheRedis可以很方便地实现数据缓存,下面是具体的步骤: 1. 配置Redis 首先需要在项目引入Redis相关的依赖,如下: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> ``` 然后在application.properties文件配置Redis的连接信息,如下: ```properties spring.redis.host=127.0.0.1 spring.redis.port=6379 spring.redis.password=123456 ``` 2. 配置SpringCacheSpringBoot,可以使用@Cacheable、@CachePut、@CacheEvict等注解来实现缓存,但是需要配置一个CacheManager来管理缓存。可以使用RedisCacheManager来管理Redis缓存,如下: ```java @Configuration @EnableCaching public class CacheConfig extends CachingConfigurerSupport { @Bean public RedisConnectionFactory redisConnectionFactory() { JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory(); jedisConnectionFactory.setHostName("127.0.0.1"); jedisConnectionFactory.setPort(6379); jedisConnectionFactory.setPassword("123456"); return jedisConnectionFactory; } @Bean public RedisTemplate<String, Object> redisTemplate() { RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>(); redisTemplate.setConnectionFactory(redisConnectionFactory()); redisTemplate.setDefaultSerializer(new StringRedisSerializer()); redisTemplate.setKeySerializer(new StringRedisSerializer()); redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer()); return redisTemplate; } @Bean public CacheManager cacheManager() { RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig() .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer())) .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer())); RedisCacheManager redisCacheManager = RedisCacheManager.builder(redisConnectionFactory()) .cacheDefaults(redisCacheConfiguration) .transactionAware() .build(); return redisCacheManager; } } ``` 其redisConnectionFactory方法是用来创建Redis连接的,redisTemplate方法是用来进行Redis操作的,cacheManager方法是用来创建RedisCacheManager的。 3. 使用缓存 有了上面的配置之后,就可以在项目使用缓存了。例如,我们可以对一个方法进行缓存,如下: ```java @Service public class UserService { @Autowired private UserRepository userRepository; @Cacheable(value = "userCache", key = "#id") public User getUserById(Long id) { System.out.println("getUserById from DB"); return userRepository.findById(id).orElse(null); } } ``` 在这个例子,我们使用了@Cacheable注解将getUserById方法进行了缓存,value属性表示缓存的名称,key属性表示缓存的键值。如果缓存已经有了对应的数据,则直接从缓存获取数据,否则就从数据库获取数据,并将数据加入到缓存。 4. 清除缓存 有时候需要从缓存清除某些数据,可以使用@CacheEvict注解来实现,如下: ```java @Service public class UserService { @Autowired private UserRepository userRepository; @Cacheable(value = "userCache", key = "#id") public User getUserById(Long id) { System.out.println("getUserById from DB"); return userRepository.findById(id).orElse(null); } @CacheEvict(value = "userCache", key = "#id") public void deleteUserById(Long id) { userRepository.deleteById(id); } } ``` 在这个例子,我们使用了@CacheEvict注解将deleteUserById方法进行了缓存清除,value属性表示缓存的名称,key属性表示缓存的键值。如果有对应的数据,则从缓存清除该数据。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值