springboot 集成redis 集群

maven 依赖

        <!-- redis -->
        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-redis</artifactId>
            <exclusions>
                <exclusion>
                    <artifactId>slf4j-api</artifactId>
                    <groupId>org.slf4j</groupId>
                </exclusion>
            </exclusions>
        </dependency>

1.配置文件

#redis 集群节点信息
spring.redis.cluster.nodes=10.3.4.184:6379,10.3.4.184:6380,10.3.4.184:6381,10.3.4.185:6382,10.3.4.185:6383,10.3.4.185:6384
#redis 命令超时时间
spring.redis.commandTimeout=5000
spring.redis.password=
#redis最大连接数
spring.redis.pool.max-total=30
# redis最大空闲连接数
spring.redis.pool.max-idle=10
# redis最小空闲连接数
spring.redis.pool.min-idle=5
# redis 最大活跃时间
spring.redis.pool.max-active=5000
# redis 连接最大等待时间
spring.redis.pool.max-wait=1500
# 每次逐出检查时,逐出的最大数目
spring.redis.pool.numTestsPerEvictionRun=1024
# 逐出扫描的时间间隔(毫秒)如果为负数,则不运行逐出线程,默认-1
spring.redis.pool.timeBetweenEvictionRunsMillis=30000
# 逐出连接的最小空闲时间 默认1800000毫秒(30分钟)
spring.redis.pool.minEvictableIdleTimeMillis=1800000
# 对象空闲多久后逐出,当空闲时间> 该值 且空闲连接 > 最大空闲数 ,不再根据minEvictableIdleTimeMillis 判断
spring.redis.pool.softMinEvictableIdleTimeMills=10000
# 获取连接时检查有效性,默认false
spring.redis.pool.testOnBorrow=true
# 在空闲时检查有效性,默认false
spring.redis.pool.testWhileIdle=true
spring.redis.pool.blockWhenExhausted=false

2.增加配置类,加载配置到配置类RedisConfig.java(@EnableCaching 注解驱动的缓存管理功能 )

package com.cfcc.bigdata.base.config.redis;

import com.cfcc.bigdata.base.config.cache.AbstractCacheConfig;
import com.cfcc.bigdata.common.base.mto.MessageEntity;
import com.cfcc.bigdata.voucher.thread.MessageQueue;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisClusterConfiguration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisNode;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import redis.clients.jedis.JedisCluster;
import redis.clients.jedis.JedisPoolConfig;

import java.util.HashMap;
import java.util.Map;

/**
* Created by gzy
*/
@Configuration
@EnableCaching
public class RedisConfig  extends AbstractCacheConfig {

    @Value("${spring.redis.cluster.nodes}")
    private String nodes;

    @Value("${spring.redis.commandTimeout}")
    private int commandTimeout;

    @Value("${spring.redis.pool.max-idle}")
    private int maxIdle;

    @Value("${spring.redis.pool.max-wait}")
    private long maxWait;

    @Value("${spring.redis.pool.max-active}")
    private long maxActive;

    @Value("${spring.redis.pool.min-idle}")
    private int minIdle;

    @Value("${spring.redis.pool.numTestsPerEvictionRun}")
    private int numTestsPerEvictionRun;

    @Value("${spring.redis.pool.timeBetweenEvictionRunsMillis}")
    private long timeBetweenEvictionRunsMilliss;

    @Value("${spring.redis.pool.minEvictableIdleTimeMillis}")
    private long minEvictableIdleTimeMillis;

    @Value("${spring.redis.pool.softMinEvictableIdleTimeMills}")
    private long softMinEvictableIdleTimeMills;

    @Value("${spring.redis.pool.testOnBorrow}")
    private boolean testOnBorrow;

    @Value("${spring.redis.pool.testWhileIdle}")
    private boolean testWhileIdle;

    @Value("${spring.redis.pool.blockWhenExhausted}")
    private boolean blockWhenExhausted;



    /*对象池配置*/
    @Bean
    public JedisPoolConfig jedisPoolConfig() {
        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
        jedisPoolConfig.setMaxIdle(maxIdle);
        jedisPoolConfig.setMaxWaitMillis(maxWait);
        jedisPoolConfig.setMinIdle(minIdle);
        jedisPoolConfig.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
        jedisPoolConfig.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMilliss);
        jedisPoolConfig.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMilliss);
        jedisPoolConfig.setNumTestsPerEvictionRun(numTestsPerEvictionRun);
        jedisPoolConfig.setSoftMinEvictableIdleTimeMillis(softMinEvictableIdleTimeMills);
        jedisPoolConfig.setTestOnBorrow(testOnBorrow);
        jedisPoolConfig.setBlockWhenExhausted(blockWhenExhausted);
        jedisPoolConfig.setTestWhileIdle(testWhileIdle);

        return jedisPoolConfig;

    }

   /* @Bean
    public JedisCluster getJedisCluster() {
        String[] nNodes = nodes.split(",");
        Set<HostAndPort> nodes = new HashSet<>();
        //分割集群节点
        for (String node : nNodes) {
            String[] hp = node.split(":");
            nodes.add(new HostAndPort(hp[0], Integer.parseInt(hp[1])));
        }

        return new JedisCluster(nodes, commandTimeout,jedisPoolConfig());

    }*/

    /**
     *  通过反射获取JedisCluster
     * @param factory
     * @return
     */
   @Bean
   public JedisCluster redisCluster(RedisConnectionFactory factory) {
       Object obj = null;
       try {
           obj = getFieldValueByObject(factory, "cluster");
       } catch (Exception e) {

       }
       return (JedisCluster)obj;
   }

    @Bean(name = "clusterConfig")
    public RedisClusterConfiguration clusterConfig() {

        RedisClusterConfiguration redisClusterConfiguration = new RedisClusterConfiguration();
        String[] nNodes = nodes.split(",");
        //分割集群节点
        for (String node : nNodes) {
            String[] hp = node.split(":");
            RedisNode redis = new RedisNode(hp[0], Integer.parseInt(hp[1]));
            redisClusterConfiguration.addClusterNode(redis);
        }

        return redisClusterConfiguration;

    }


    @Bean(name = "factory")
    public RedisConnectionFactory jedisConnectionFactory(RedisClusterConfiguration clusterConfiguration) {
        JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory(clusterConfiguration);
        jedisConnectionFactory.setPoolConfig(jedisPoolConfig());
        jedisConnectionFactory.setTimeout(30000);
        jedisConnectionFactory.setUsePool(true);
        return jedisConnectionFactory;
    }

    /**
     * 自定义RedisTemplate,修改序列化方式
     *
     * @param factory
     * @return
     */
    @Bean(name = "sqlCachRedisTemplate")
    @Primary
    public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        final StringRedisTemplate redisTemplate = new StringRedisTemplate(redisConnectionFactory);
        RedisSerializer<String> redisSerializer = new StringRedisSerializer();
        redisTemplate.setKeySerializer(redisSerializer);
        redisTemplate.setValueSerializer(getJsonSerializer());
        redisTemplate.setHashKeySerializer(redisSerializer);
        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }

    @Bean(name = "msgRedisTemplate")
    public RedisTemplate<String, MessageEntity> messageRedisTemplate(RedisConnectionFactory redisConnectionFactory) {

        RedisTemplate<String, MessageEntity> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        RedisSerializer<String> redisSerializer = new StringRedisSerializer();
        redisTemplate.setHashKeySerializer(redisSerializer);
        redisTemplate.setKeySerializer(redisSerializer);
        redisTemplate.setValueSerializer(getJsonSerializer());
        redisTemplate.setHashValueSerializer(getJsonSerializer());
        //开启事务支持,这个事务有点鸡肋不支持回滚
        redisTemplate.setEnableTransactionSupport(true);
        return redisTemplate;
    }

    /**
     * 缓存分页查询的数据
     * @param factory
     * @return
     */
    @Bean(name = "pageCacheRedisTemplate")
    public RedisTemplate<String, Object> redisPageTemplate(RedisConnectionFactory factory) {
        final RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(factory);
        RedisSerializer<String> redisSerializer = new StringRedisSerializer();
        redisTemplate.setKeySerializer(redisSerializer);
        redisTemplate.setValueSerializer(getJsonSerializer());
        redisTemplate.setHashKeySerializer(redisSerializer);
        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }


    /**
     * 定义Redis的缓存管理器
     * @return
     */
    @Bean
    public CacheManager redisCacheManager(@Qualifier("sqlCachRedisTemplate") RedisTemplate redisTemplate) {
        RedisCacheManager redisCacheManager = new RedisCacheManager(redisTemplate);
        //设置默认缓存过期时间是7Day
        redisCacheManager.setDefaultExpiration(7 * 24 * 60 * 60);
        Map<String, Long> expiresMap = new HashMap<>();
        //设置sql 的缓存时间 30 M
        expiresMap.put("paramCache", 1800l);
        redisCacheManager.setExpires(expiresMap);

        return redisCacheManager;
    }


    /**
     * 设置数据序列化方式为json
     *
     * @return
     */
    @SuppressWarnings({"rawtypes", "unchecked"})
    private Jackson2JsonRedisSerializer<Object> getJsonSerializer() {
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);
        return jackson2JsonRedisSerializer;
    }

AbstractCacheConfig.java (这里对sql 查询结果生成缓存的Key的方法进行了重写 )

package com.cfcc.bigdata.base.config.cache;

import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.interceptor.KeyGenerator;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;

/**
* @author gzy
* @version : 1.0
* @date : 2018/11/17 0017
*/
public abstract class AbstractCacheConfig extends CachingConfigurerSupport {
    /**
     * 继承并修改缓存key的生成方式
     */
    @SuppressWarnings("rawtypes")
    @Override
    public KeyGenerator keyGenerator() {
        return new KeyGenerator() {
            @Override
            public Object generate(Object target, Method method, Object... params) {
                StringBuilder sb = new StringBuilder();
                sb.append(target.getClass().getName());
                sb.append(".");
                sb.append(method.getName());
                for (Object param : params) {
                    if (param instanceof List) {
                        sb.append("#[");
                        List paramList = (List) param;
                        for (Object paramObj : paramList) {
                            sb.append("&" + ToStringBuilder.reflectionToString(paramObj, ToStringStyle.SHORT_PREFIX_STYLE));
                        }
                        sb.append("]");
                    } else if (param instanceof Map) {
                        sb.append("#[");
                        Map paramMap = (Map) param;
                        for (Object key : paramMap.keySet()) {
                            Object value = paramMap.get(key);
                            sb.append("&");
                            sb.append(ToStringBuilder.reflectionToString(key, ToStringStyle.SHORT_PREFIX_STYLE));
                            sb.append(":");
                            sb.append(ToStringBuilder.reflectionToString(value, ToStringStyle.SHORT_PREFIX_STYLE));
                        }
                        sb.append("]");
                    } else {
                        sb.append("#" + ToStringBuilder.reflectionToString(param, ToStringStyle.SHORT_PREFIX_STYLE));
                    }
                }
                return sb.toString();
            }
        };
    }

    public Object getFieldValueByObject(Object object, String targetFieldName) throws IllegalAccessException {

        // 获取该对象的Class
        Class objClass = object.getClass();
        // 获取所有的属性数组
        Field[] fields = objClass.getDeclaredFields();

        for (Field field : fields) {
            //属性名称
            field.setAccessible(true);
            String currentFieldName = field.getName();
            if (currentFieldName.equals(targetFieldName)) {
                return field.get(object);
            }
        }
        return  null;

    }
}

3.使用缓存(所有的Service 继承此类就可以使用缓存管理功能了)

package com.cfcc.bigdata.common.base.service;

import com.cfcc.bigdata.common.base.helper.PageQueryHelper;
import com.cfcc.bigdata.common.base.vo.PropertyFilter;
import com.cfcc.bigdata.common.base.mybatis.base.BaseMapper;
import com.cfcc.bigdata.common.base.vo.EasyUIDatagridParam;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
* 所有Service的父类,提供通用CURD方法的默认实现。
*
*/
@Transactional
@CacheConfig(cacheNames = "paramCache")
public abstract class BaseCacheService<T extends Serializable> {

    @Autowired
    private BaseMapper<T> mapper;

    /**
     * 根据实体中的属性值进行查询,查询条件使用等号
     *
     * @param record
     * @return
     */
    @Cacheable
    @Transactional(readOnly = true)
    public List<T> select(T record) {
        return mapper.select(record);
    }

    /**
     * 根据主键字段进行查询,方法参数必须包含完整的主键属性,查询条件使用等号
     *
     * @param key
     * @return
     */
    @Cacheable
    @Transactional(readOnly = true)
    public T selectByPrimaryKey(Object key) {
        return mapper.selectByPrimaryKey(key);
    }

    /**
     * 查询全部结果,select(null)方法能达到同样的效果
     *
     * @return
     */
    @Cacheable
    @Transactional(readOnly = true)
    public List<T> selectAll() {
        return mapper.selectAll();
    }

    /**
     * 根据条件分页查询记录列表
     *
     * @param page
     *            当前页码
     * @param rows
     *            每页记录数
     * @param record
     *            条件对象
     * @return
     */
    @Cacheable
    @Transactional(readOnly = true)
    public PageInfo<T> selectPage(Integer page, Integer rows, T record) {
        PageHelper.startPage(page, rows);
        List<T> list = mapper.select(record);
        return new PageInfo<>(list);

    }

    /**
     * 根据条件分页查询记录列表
     *
     * @param page
     *            当前页码
     * @param rows
     *            每页记录数
     * @param example
     *            条件对象
     * @return
     */
    @Cacheable
    @Transactional(readOnly = true)
    public PageInfo<T> selectPageByExample(Integer page, Integer rows, Example example) {
        PageHelper.startPage(page, rows);
        List<T> list = mapper.selectByExample(example);
        return new PageInfo<>(list);
    }

    /**
     * 根据实体中的属性进行查询,只能有一个返回值,有多个结果是抛出异常,查询条件使用等号
     *
     * @param record
     * @return
     */
    @Cacheable
    @Transactional(readOnly = true)
    public T selectOne(T record) {
        return mapper.selectOne(record);
    }

    /**
     * 根据实体中的属性查询总数,查询条件使用等号
     *
     * @param record
     * @return
     */
    @Transactional(readOnly = true)
    public int selectCount(T record) {
        return mapper.selectCount(record);
    }

    /**
     * 根据主键字符串进行查询,类中只有存在一个带有@Id注解的字段
     * <p>
     * 通过操作ids字符串进行操作,ids 如 "1,2,3" 这种形式的字符串,这个方法要求实体类中有且只有一个带有@Id注解的字段,否则会抛出异常
     * </p>
     *
     * @param ids
     * @return
     */
    @Cacheable
    @Transactional(readOnly = true)
    public List<T> selectByIds(String ids) {
        if (ids != null && !"".equals(ids)) {
            List<T> list = new ArrayList<>();
            String[] idArray = ids.split(",");
            for (String id : idArray) {
                list.add(mapper.selectByPrimaryKey(id));
            }
            return list;
        }
        return Collections.emptyList();
    }

    /**
     * 根据Example条件进行查询
     * <p>
     * 重点:这个查询支持通过Example类指定查询列,通过selectProperties方法指定查询列
     * </p>
     *
     * @param example
     * @return
     */
    @Cacheable
    @Transactional(readOnly = true)
    public List<T> selectByExample(Object example) {
        return mapper.selectByExample(example);
    }

    /**
     * 根据Example条件进行查询总数
     *
     * @param example
     * @return
     */
    @Transactional(readOnly = true)
    public int selectCountByExample(Object example) {
        return mapper.selectCountByExample(example);
    }

    /**
     * 根据通用条件进行分页查询
     *
     * @param param
     *            easyui传来的参数信息
     * @param filters
     *            通用条件对象
     * @param entityClass
     *            查询的实体对象类型
     * @return
     */
    @Cacheable
    @Transactional(readOnly = true)
    public PageInfo<T> selectEasyUIPageByFilters(final EasyUIDatagridParam param, final List<PropertyFilter> filters, Class<?> entityClass) {
        PageQueryHelper pageQueryHelper = new PageQueryHelper();
        Example example = pageQueryHelper.generateExampleByFilters(param, filters, entityClass);
        return selectPageByExample(param.getPage(), param.getRows(), example);
    }

    /**
     * 根据通用条件查询所有符合条件记录
     *
     * @param param
     *            easyui传来的参数信息
     * @param filters
     *            通用条件对象
     * @param entityClass
     *            查询的实体对象类型
     * @return
     */
    @Cacheable
    @Transactional(readOnly = true)
    public List<T> selectEasyUIAllByFilters(final EasyUIDatagridParam param, final List<PropertyFilter> filters, Class<?> entityClass) {
        PageQueryHelper pageQueryHelper = new PageQueryHelper();
        Example example = pageQueryHelper.generateExampleByFilters(param, filters, entityClass);
        return mapper.selectByExample(example);
    }

    /**
     * 保存一个实体,null的属性也会保存,不会使用数据库默认值
     * beforeInvocation 在执行sql之前清除缓存
     * @param record
     * @return
     */
    @CacheEvict(beforeInvocation = true, allEntries = true)
    public int insert(T record) {
        return mapper.insert(record);
    }

    /**
     * 保存一个实体,null的属性不会保存,会使用数据库默认值
     *
     * @param record
     * @return
     */
    @CacheEvict(beforeInvocation = true, allEntries = true)
    public int insertSelective(T record) {
        return mapper.insertSelective(record);
    }

    /**
     * 批量插入,支持批量插入的数据库可以使用,例如MySQL,H2等
     *
     * @param recordList
     * @return
     */
    @CacheEvict(beforeInvocation = true, allEntries = true)
    public int insertList(List<T> recordList) {
        return mapper.insertListUseAllCols(recordList);
    }

    /**
     * 根据主键更新实体全部字段,null值会被更新
     *
     * @param record
     * @return
     */
    @CacheEvict(beforeInvocation = true, allEntries = true)
    public int updateByPrimaryKey(T record) {
        return mapper.updateByPrimaryKey(record);
    }

    /**
     * 根据主键更新属性不为null的值
     *
     * @param record
     * @return
     */
    @CacheEvict(beforeInvocation = true, allEntries = true)
    public int updateByPrimaryKeySelective(T record) {
        return mapper.updateByPrimaryKeySelective(record);
    }

    /**
     * 根据Example条件更新实体record包含的全部属性,null值会被更新
     *
     * @param record
     * @param example
     * @return
     */
    @CacheEvict(beforeInvocation = true, allEntries = true)
    public int updateByExample(T record, Object example) {
        return mapper.updateByExample(record, example);
    }

    /**
     * 根据Example条件更新实体record包含的不是null的属性值
     *
     * @param record
     * @param example
     * @return
     */
    @CacheEvict(beforeInvocation = true, allEntries = true)
    public int updateByExampleSelective(T record, Object example) {
        return mapper.updateByExampleSelective(record, example);
    }
    
    /**
     * 批量更新
     *
     * @param recordList
     */
    @CacheEvict(beforeInvocation = true, allEntries = true)
    public void updateList(List<T> recordList) {
        for(T t : recordList) {
            mapper.updateByPrimaryKey(t);
        }
    }

    /**
     * 根据实体属性作为条件进行删除,查询条件使用等号
     *
     * @param record
     * @return
     */
    @CacheEvict(beforeInvocation = true, allEntries = true)
    public int delete(T record) {
        return mapper.delete(record);
    }

    /**
     * 根据主键字符串进行删除,类中只有存在一个带有@Id注解的字段
     * <p>
     * 通过操作ids字符串进行操作,ids 如 "1,2,3" 这种形式的字符串,这个方法要求实体类中有且只有一个带有@Id注解的字段,否则会抛出异常
     * </p>
     *
     * @param ids
     * @return
     */
    @CacheEvict(beforeInvocation = true, allEntries = true)
    public int deleteByIds(String ids) {
        if (ids != null && !"".equals(ids)) {
            String[] idArray = ids.split(",");
            for (String id : idArray) {
                mapper.deleteByPrimaryKey(id);
            }
            return idArray.length;
        }
        return 0;
    }

    /**
     * 根据主键字段进行删除,方法参数必须包含完整的主键属性
     *
     * @param key
     * @return
     */
    @CacheEvict(beforeInvocation = true, allEntries = true)
    public int deleteByPrimaryKey(Object key) {
        return mapper.deleteByPrimaryKey(key);
    }

    /**
     * 根据Example条件删除数据
     *
     * @param example
     * @return
     */
    @CacheEvict(beforeInvocation = true, allEntries = true)
    public int deleteByExample(Object example) {
        return mapper.deleteByExample(example);
    }
    
    /**
     * 刷新缓存
     */
    @CacheEvict(beforeInvocation = true, allEntries = true)
    public void reload() {

    }
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

独行客-编码爱好者

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值