SpringBoot+redis clusterクラスタ構築

83584 ワード

SpringBoot+redis clusterクラスタ構築
前言:本文はもう一つのRedisクラスタポリシーとクラスタインスタンス(クラスタノードの追加、削除、再割り当てslot実戦)の博文に対して構築したJavaプロジェクトはredisクラスタの完全なプロセスの学習に用いられ、参考に供する.本明細書のコードはコードクラウドオープンソースプロジェクトに関する資料1を参照する.環境(1).springboot 2.0 (2).redis 4.0.10 2.関連コード1,pom.xmlファイル
 

    4.0.0
    
        org.springframework.boot
        spring-boot-starter-parent
        2.2.4.RELEASE
         
    
    spring.boot
    demo
    0.0.1-SNAPSHOT
    jar
    jpa
    Demo project for Spring Boot

    
        UTF-8
        org.tdcg.Application
        1.8
    
    
        
            org.springframework.boot
            spring-boot-starter-data-jpa
        
        
            org.springframework.boot
            spring-boot-starter-thymeleaf
        
        
            org.springframework.boot
            spring-boot-starter-web
        
        
            com.alibaba
            druid
            1.1.6
        
        
            mysql
            mysql-connector-java
            runtime
        
        
            org.springframework.boot
            spring-boot-starter-test
        
        
            org.projectlombok
            lombok
            1.18.10
        
        
        
            org.bgee.log4jdbc-log4j2
            log4jdbc-log4j2-jdbc4.1
            1.16
        
        
        
            org.springframework.boot
            spring-boot-configuration-processor
            true
        
        
        
        
            org.springframework.boot
            spring-boot-starter-data-redis
            
                
                    io.lettuce
                    lettuce-core
                
            
        
        
        
        
            redis.clients
            jedis
        
        
            com.alibaba
            fastjson
            1.2.31
        
        
            org.springframework
            spring-context
            5.2.3.RELEASE
        
        
            log4j
            log4j
            1.2.17
        
        
            junit
            junit
            4.12
            test
        
    
    
        
            
                org.springframework.boot
                spring-boot-maven-plugin
            
        
        SpringBootJap
    


二、プロファイルアプリケーション.properties
#datasource#mysql   #
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/study-jpa?useUnicode=true&characterEncoding=utf8&serverTimezone=UTC
spring.datasource.username = root
spring.datasource.password = 123456
spring.datasource.driverClassName = com.mysql.cj.jdbc.Driver
spring.datasource.max-active=20
spring.datasource.max-idle=8
spring.datasource.min-idle=8
spring.datasource.initial-size=10
# server
server.port: 8081      

三、redisプロファイルredis.properties
#  redis     ip    ,        “,”  。
spring.redis.cluster.nodes=192.168.0.108:8001,192.168.0.108:8002,192.168.0.108:8003,192.168.0.108:8004,192.168.0.108:8005,192.168.0.108:8006
#           (                ,                )
#        
spring.redis.cluster.timeout=5000
#         
spring.redis.cluster.max-attempts=3
#      
spring.redis.cluster.soTimeout=3000
spring.redis.cluster.max-redirects=3

三、フォルダredis構成を作成し、それに従ってredis初期化構成RedisConfiguration、JedisClusterFactoryファクトリクラス、カスタムキャッシュインタフェースICacheManager及びredisクライアント実装クラスJedisCacheManagerを作成する
(一)redis初期化構成RedisConfiguration
package spring.boot.jpa.redis;


import com.google.common.collect.Sets;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;

import java.util.Collections;
import java.util.Set;

/**
 * @Title: RedisConfiguration
 * @Description: redis     
 * @Author: zyq
 * @date: 2020/02/12
 * @Version: V1.0
 */
@Configuration

@PropertySource("classpath:redis.properties")
public class RedisConfiguration extends CachingConfigurerSupport {

    @Bean(name = "jedisCluster")
    public JedisClusterFactory jedisCluster(
            @Value("${spring.redis.cluster.nodes}") String host,
            @Value("${spring.redis.cluster.timeout}") int connectionTimeout,
            @Value("${spring.redis.cluster.soTimeout}") int soTimeout) {
        JedisClusterFactory jedisClusterFactory = new JedisClusterFactory();
        jedisClusterFactory.setConnectionTimeout(connectionTimeout);
       // jedisClusterFactory.setMaxRedirections(maxRedirections);
        jedisClusterFactory.setSoTimeout(soTimeout);
        String[] split = host.split(",");
        Set<String> hosts = Sets.newHashSet();
        Collections.addAll(hosts, split);
        jedisClusterFactory.setJedisClusterNodes(hosts);
        return jedisClusterFactory;
    }
}

(二)JedisClusterFactory工場類
package spring.boot.jpa.redis;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.JedisCluster;
import java.text.ParseException;
import java.util.HashSet;
import java.util.Set;

/**
 * @Title: JedisClusterFactory
 * @Description:    
 * @Author: zyq
 * @date: 2020/02/12
 * @Version: V1.0
 */
public class JedisClusterFactory implements FactoryBean<JedisCluster>, InitializingBean {
	private GenericObjectPoolConfig genericObjectPoolConfig = new GenericObjectPoolConfig();
	private JedisCluster jedisCluster;
	private int connectionTimeout = 2000;
	private int soTimeout = 3000;
	private int maxRedirections = 5;
	private Set<String> jedisClusterNodes;
	@Override
	public void afterPropertiesSet() throws Exception {
		if (jedisClusterNodes == null || jedisClusterNodes.size() == 0) {
			throw new NullPointerException("jedisClusterNodes is null.");
		}
		Set<HostAndPort> haps = new HashSet<HostAndPort>();
		for (String node : jedisClusterNodes) {
			String[] arr = node.split(":");
			if (arr.length != 2) {
				throw new ParseException("node address error !",node.length()-1);
			}
			haps.add(new HostAndPort(arr[0], Integer.valueOf(arr[1])));
		}
		jedisCluster = new JedisCluster(haps, connectionTimeout, soTimeout, maxRedirections, genericObjectPoolConfig);
	}
	@Override
	public JedisCluster getObject() throws Exception {
		return jedisCluster;
	}
	@Override
	public Class<?> getObjectType() {
		return (this.jedisCluster != null ? this.jedisCluster.getClass() : JedisCluster.class);
	}
	@Override
	public boolean isSingleton() {
		return true;
	}

	public GenericObjectPoolConfig getGenericObjectPoolConfig() {
		return genericObjectPoolConfig;
	}
	public void setGenericObjectPoolConfig(GenericObjectPoolConfig genericObjectPoolConfig) {
		this.genericObjectPoolConfig = genericObjectPoolConfig;
	}

	public JedisCluster getJedisCluster() {
		return jedisCluster;
	}

	public void setJedisCluster(JedisCluster jedisCluster) {
		this.jedisCluster = jedisCluster;
	}

	public int getConnectionTimeout() {
		return connectionTimeout;
	}

	public void setConnectionTimeout(int connectionTimeout) {
		this.connectionTimeout = connectionTimeout;
	}

	public int getSoTimeout() {
		return soTimeout;
	}

	public void setSoTimeout(int soTimeout) {
		this.soTimeout = soTimeout;
	}

	public int getMaxRedirections() {
		return maxRedirections;
	}

	public void setMaxRedirections(int maxRedirections) {
		this.maxRedirections = maxRedirections;
	}

	public Set<String> getJedisClusterNodes() {
		return jedisClusterNodes;
	}

	public void setJedisClusterNodes(Set<String> jedisClusterNodes) {
		this.jedisClusterNodes = jedisClusterNodes;
	}
}

(三)カスタムキャッシュ操作インタフェースICacheManager
package spring.boot.jpa.redis;

import java.io.Serializable;
import java.util.List;
import java.util.Map;

/**
 * @Title: ICacheManager
 * @Description:     ,    
 * @Author: zyq
 * @date: 2020/02/12
 * @Version: V1.0
 */
public interface ICacheManager {

    /**
     *     key   
     *
     * @param cacheKey
     * @return
     */
    public Object getCache(Serializable cacheKey);

    /**
     *        key-value,       ,    
     *
     * @param cacheKey
     * @param objValue
     * @param expiration
     * @return
     */
    public boolean putCache(Serializable cacheKey, Object objValue, int expiration);

    /**
     *     
     *
     * @param cacheKey
     */
    public Long removeCache(Serializable cacheKey);

    /**
     *    list       , list      
     *
     * @param cacheKey
     * @param objValue
     * @return
     */
    public boolean putListCache(Serializable cacheKey, Object objValue);

    /**
     *    list       ,       
     *
     * @param cacheKey
     * @param objValue
     * @param index
     * @return
     */
    public boolean putListCache(Serializable cacheKey, Object objValue, int index);

    /**
     *     ,      
     *
     * @param cacheKey
     * @param start            0
     * @param end              -1
     * @return
     */
    public List<Object> getListCache(Serializable cacheKey, int start, int end);

    /**
     *     
     *
     * @param cacheKey
     * @return
     */
    public List<Object> getListCache(Serializable cacheKey);

    /**
     *   list  
     *
     * @param cacheKey
     * @param start        
     * @param end          
     * @return
     */
    public boolean trimListCache(Serializable cacheKey, int start, int end);

    /**
     *   map  
     *
     * @param cacheKey
     * @param map
     * @return
     */
    public boolean putMapCache(Serializable cacheKey, Map<Object, Object> map);

    /**
     *   map    
     *
     * @param cacheKey
     * @param mapKey
     * @return
     */
    public boolean deleteMapCache(Serializable cacheKey, Serializable mapKey);


    /**
     *   map   
     *
     * @param cacheKey
     * @param mapKey
     * @return
     */
    public Object getMapValueCache(Serializable cacheKey, Serializable mapKey);
}

(四)redisクライアント実装クラスJedisCacheManager
package spring.boot.jpa.redis.impl;

import com.alibaba.druid.util.StringUtils;
import org.springframework.stereotype.Service;
import redis.clients.jedis.JedisCluster;
import spring.boot.jpa.redis.ICacheManager;
import spring.boot.jpa.redis.SerializingUtil;

import javax.annotation.Resource;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

/**
 * @Title: JedisCacheManager
 * @Description:     
 * @Author: zyq
 * @date: 2020/02/12
 * @Version: V1.0
 */
@Service("iCacheManager")
public class JedisCacheManager implements ICacheManager {

    private static final String JEDIS_SET_RETURN_OK = "OK";

    @Resource
    private JedisCluster jedisCluster;

    @Override
    public Object getCache(Serializable cacheKey) {
        return SerializingUtil.deserialize((byte[]) jedisCluster.get(SerializingUtil.serialize(cacheKey)));
    }

    @Override
    public boolean putCache(Serializable cacheKey, Object objValue, int expiration) {
        String result = jedisCluster.setex(SerializingUtil.serialize(cacheKey), expiration, SerializingUtil.serialize(objValue));
        if (StringUtils.equals(JEDIS_SET_RETURN_OK, result)) {
            return true;
        }
        return false;
    }

    @Override
    public Long removeCache(Serializable cacheKey) {
        return jedisCluster.del(SerializingUtil.serialize(cacheKey));
    }

    @Override
    public boolean putListCache(Serializable cacheKey, Object objValue) {
        Long num = jedisCluster.rpush(SerializingUtil.serialize(cacheKey), SerializingUtil.serialize(objValue));
        if (num > 0) {
            return true;
        }
        return false;
    }

    @Override
    public boolean putListCache(Serializable cacheKey, Object objValue, int index) {
        String result = jedisCluster.lset(SerializingUtil.serialize(cacheKey), index, SerializingUtil.serialize(objValue));
        if (StringUtils.equals(JEDIS_SET_RETURN_OK, result)) {
            return true;
        }
        return false;
    }

    @Override
    public List<Object> getListCache(Serializable cacheKey, int start, int end) {
        List<byte[]> list = jedisCluster.lrange(SerializingUtil.serialize(cacheKey), start, end);
        if (null != list && list.size() > 0) {
            List<Object> objList = new ArrayList<Object>();
            for (byte[] b : list) {
                objList.add(SerializingUtil.deserialize(b));
            }
            return objList;
        }
        return null;
    }

    @Override
    public List<Object> getListCache(Serializable cacheKey) {
        return getListCache(cacheKey, 0, -1);
    }

    @Override
    public boolean trimListCache(Serializable cacheKey, int start, int end) {
        String result = jedisCluster.ltrim(SerializingUtil.serialize(cacheKey), start, end);
        if (StringUtils.equals(JEDIS_SET_RETURN_OK, result)) {
            return true;
        }
        return false;
    }

    @Override
    public boolean putMapCache(Serializable cacheKey, Map<Object, Object> map) {
        if (null != map && !map.isEmpty()) {
            Map<byte[], byte[]> byteMap = new HashMap<byte[], byte[]>();
            for (Entry<Object, Object> entry : map.entrySet()) {
                byteMap.put(SerializingUtil.serialize(entry.getKey()), SerializingUtil.serialize(entry.getValue()));
            }
            String result = jedisCluster.hmset(SerializingUtil.serialize(cacheKey), byteMap);
            if (StringUtils.equals(JEDIS_SET_RETURN_OK, result)) {
                return true;
            }
            return true;
        }
        return false;
    }

    @Override
    public boolean deleteMapCache(Serializable cacheKey, Serializable mapKey) {
        Long result = jedisCluster.hdel(SerializingUtil.serialize(cacheKey), SerializingUtil.serialize(mapKey));
        if (result > 0) {
            return true;
        }
        return false;
    }


    @Override
    public Object getMapValueCache(Serializable cacheKey, Serializable mapKey) {
        List<byte[]> list = jedisCluster.hmget(SerializingUtil.serialize(cacheKey), SerializingUtil.serialize(mapKey));
        if (null != list && list.size() > 0) {
            return SerializingUtil.deserialize(list.get(0));
        }
        return null;
    }

}


(五)シーケンス化ツールクラス
package spring.boot.jpa.redis;
import org.apache.log4j.Logger;
import org.springframework.cache.CacheManager;
import java.io.*;
/**
 * @Title: SerializingUtil
 * @Package: org.tdcg.util
 * @Description:       ,  byte[] Object       .
 * @Author: zyq
 * @date: 2020/02/12
 * @Version: V1.0
 */
public class SerializingUtil {

    private static final Logger logger = Logger.getLogger(CacheManager.class);

    /**
     *     :    Bean       .
     *
     * @param source       
     * @return          
     * @throws Exception
     */
    public static byte[] serialize(Object source) {
        ByteArrayOutputStream byteOut = null;
        ObjectOutputStream ObjOut = null;
        try {
            byteOut = new ByteArrayOutputStream();
            ObjOut = new ObjectOutputStream(byteOut);
            ObjOut.writeObject(source);
            ObjOut.flush();
        } catch (IOException e) {
            logger.error(source.getClass().getName() + " serialized error !", e);
        } finally {
            try {
                if (null != ObjOut) {
                    ObjOut.close();
                }
            } catch (IOException e) {
                ObjOut = null;
            }
        }
        return byteOut.toByteArray();
    }

    /**
     *     :             Bean.
     *
     * @param source              
     * @return         Bean
     * @throws Exception
     */
    public static Object deserialize(byte[] source) {
        ObjectInputStream ObjIn = null;
        Object retVal = null;
        try {
            ByteArrayInputStream byteIn = new ByteArrayInputStream(source);
            ObjIn = new ObjectInputStream(byteIn);
            retVal = ObjIn.readObject();
        } catch (Exception e) {
            logger.error("deserialized error  !", e);
        } finally {
            try {
                if (null != ObjIn) {
                    ObjIn.close();
                }
            } catch (IOException e) {
                ObjIn = null;
            }
        }
        return retVal;
    }
}

(五)テストクラス
package spring.boot.jpa;


import com.google.common.collect.Maps;
import org.junit.FixMethodOrder;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.MethodSorters;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import spring.boot.jpa.entity.User;
import spring.boot.jpa.redis.impl.JedisCacheManager;

import javax.annotation.Resource;
import java.util.List;
import java.util.Map;


/**
 * @Title: JedisCacheManagerTest
 * @Description:    ,         
 *   @FixMethodOrder(MethodSorters.NAME_ASCENDING)              
 * @Author: zyq
 * @date: 2020/02/12
 * @Version: V1.0
 */
//Junit4    
@RunWith(SpringJUnit4ClassRunner.class)
//          SpringBoot   (        )
@SpringBootTest(classes={JpaApplication.class})//      
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
//   Web  ,Junit    ServletContext  web   
//@WebAppConfiguration
public class JedisCacheManagerTest {

    private final int expiration = 3600;

    @Resource
    private JedisCacheManager jedisCacheManager;

    @Test
    public void testAPutCache() throws Exception {
        boolean test = jedisCacheManager.putCache("test", "welocme redis cluster! created by tdcg!", expiration);
        assert(test);
    }
    @Test
    public void testBGetCache() throws Exception {
        Object test = jedisCacheManager.getCache("test");
        System.out.println(test);
        assert(test.equals("welocme redis cluster! created by tdcg!"));
    }
    @Test
    public void testCRemoveCache() throws Exception {
        Long test = jedisCacheManager.removeCache("test");
        assert(test == 1L);
    }
 }

これでredisクラスタコードレベルが基本的に実現し、参考にして、ご指導を歓迎します!!!