spring中Redis的集群简单实现

原创
2016/10/18 10:40
阅读数 392

通过自己在网上找资料在LINUX系统中安装reids,然后通过一个简单的deno来测试改redis集群是否可用。。

1.通过在网上下载redis的tar安装包( https://github.com/antirez/redis/archive/3.0.0-rc2.tar.gz ),上传到服务器中,

  1. tar -zxvf redis-3.0.0-rc2.tar.gz 解压
  2. mv redis-3.0.0-rc2.tar.gz redis3.0  新建文件并移动到改文件中
  3. cd /usr/local/redis3.0 
  4. make
  5. make install   安装

2.一切就绪之后,接下来就是创建集群坏境中所需要的文件

  1. 新建文件 mkdir cluster 并在改文件中新建集群的目录文件(7000/7001/7002/7003/7004/7005)
  2. cd cluster ,新建配置文件:redis.conf
  3. vi redis.conf
  4. 设置一下参数:port 7000

    daemonize yes

    cluster-enabled yes

    cluster-config-file nodes.conf

    cluster-node-timeout 5000

    appendonly yes   bind 127.0.0.1 192.168.8.98(本机IP,这一步是为了待会在window系统中可以连接该redis)

  5. 修改完redis.conf配置文件中的这些配置项之后把这个配置文件分别拷贝到7000/7001/7002/7003/7004/7005目录下面  ,并修改redis.conf文件中port的值分别对应目录的名称

  6. 分别启动这6个redis的实例:./redis.server redis.conf

    执行redis的创建集群命令创建集群 : ./redis-trib.rb  create --replicas 1 127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005

6.1执行上面的命令的时候会报错,因为是执行的ruby的脚本,需要ruby的环境

错误内容:/usr/bin/env: ruby: No such file or directory

所以需要安装ruby的环境,这里推荐使用yum install ruby安装

yum install ruby

6.2然后再执行第6步的创建集群命令,还会报错,提示缺少rubygems组件,使用yum安装

 

错误内容:

./redis-trib.rb:24:in `require': no such file to load -- rubygems (LoadError)

from ./redis-trib.rb:24

yum install rubygems

6.3再次执行第6步的命令,还会报错,提示不能加载redis,是因为缺少redis和ruby的接口,使用gem 安装

错误内容:

/usr/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:31:in `gem_original_require': no such file to load -- redis (LoadError)

from /usr/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:31:in `require'

from ./redis-trib.rb:25

 

gem install redis

 

6.4 再次执行第6步的命令,正常执行

至此redis集群即搭建成功!

   分割线--------------------------------------------------------------------------------------------------------------------------------

接下来是在spring代码中去操作该reids,demo通过大致的三层结构实现,代码有点多

1.新建文件:applicationContext-redis.xml 配置如下:

    <!-- jedis pool对象池配置 -->
    <bean name="genericObjectPoolConfig" class="org.apache.commons.pool2.impl.GenericObjectPoolConfig" >
            <property name="maxWaitMillis" value="${redis.maxWaitMillis}" />
            <property name="maxTotal" value="${redis.maxTotal}" />
            <property name="maxIdle" value="${redis.maxIdle}" />
            <property name="testOnBorrow" value="${redis.testOnBorrow}" />
    </bean>
    
<!--      使用构造方法注入:public JedisCluster(Set<HostAndPort> nodes, int timeout, final GenericObjectPoolConfig poolConfig)  -->
    <bean id="jedisCluster" class="redis.clients.jedis.JedisCluster">
        <constructor-arg index="0">
            <set>
                <bean class="redis.clients.jedis.HostAndPort">
                    <constructor-arg type="java.lang.String" value="192.168.8.98" />
                    <constructor-arg type="int" value="7000" />
                </bean>
                <bean class="redis.clients.jedis.HostAndPort">
                    <constructor-arg type="java.lang.String" value="192.168.8.98" />
                    <constructor-arg type="int" value="7001" />
                </bean>
            </set>
        </constructor-arg>
        <constructor-arg index="1" value="15000" type="int"></constructor-arg>
        <constructor-arg index="2" ref="genericObjectPoolConfig"></constructor-arg>
    </bean>

2.新建切面类:RedisCacheInterceptor

@Component
@Aspect
public class RedisCacheInterceptor {


    private Logger logger = Logger.getLogger(this.getClass());
    
    private static final String ADD = "@annotation(AddToRedis)";
    
    private static final String DELETE = "@annotation(DeleteToRedis)";
    
    private static final String GET = "@annotation(GetFromRedis)";
    
    private static final String UPDATE = "@annotation(UpdateToRedis)";
    @Autowired
    private IRedisCommandService redisCommandService;
    @Around(ADD)
    public Object add(ProceedingJoinPoint pjp) throws Throwable{
        AddToRedis anno= getAnnotation(pjp,AddToRedis.class);
        //命名空间
        String key = anno.key();

        //缓存类型
        ReadCacheType cacheType = anno.cacheType();
        //返回值
        Object fieldValue = String.valueOf(pjp.proceed());
        Object[] args = pjp.getArgs();
        //加入到缓存中
        if(args!= null && args.length>0 && args[0].getClass() == anno.classType()){
            try {
                addRedisCache(key,fieldValue.toString(),args[0],0,cacheType);
            } catch (Exception e) {
                e.printStackTrace();
            }
            
        }
        return fieldValue;
    }
    /**
     * 获取缓存信息
    *TODO:2016-10-14:上午10:06:39
    *return Object
     * @throws Throwable
     */
    @Around(value = GET)
    public Object get(ProceedingJoinPoint pjp) throws Throwable{
        GetFromRedis anno= getAnnotation(pjp,GetFromRedis.class);
        String key = anno.key();
        String fieldKey = anno.fieldKey();
        ReadCacheType cacheType = anno.cacheType();
        Object value = null;
        if(cacheType == ReadCacheType.Set){
            value = redisCommandService.smemebers(key, anno.classType());
            if(value == null){
                Log.info("[key]"+key+"cache is not exist");
                //缓存中不存在,则去数据库中查询数据
                value = pjp.proceed();
                if(value != null){
                    redisCommandService.sadd(key, value);
                    Log.info("[info]"+"[key]"+"添加缓存成功");
                }
                
            }
        }else if(cacheType == ReadCacheType.List){
            if(fieldKey != null && !fieldKey.equals("")){
                String k =  parseKey(fieldKey, getMethod(pjp), pjp.getArgs());
                value = redisCommandService.getMapValue(key, k);
                Class c = anno.classType();
                value = JSONArray.parseArray((String) value, c);
                if(value == null){
                    Log.info("[info]"+key+"cache is not find");
                    value = pjp.proceed();
                    redisCommandService.hSetMapList(key, k, (List<?>) value);
                    Log.info("[info]"+key+"has add to cache");
                }

            }
        }else if(cacheType == ReadCacheType.Map){
            if(fieldKey != null && !"".equals(fieldKey)){
                String k =  parseKey(fieldKey, getMethod(pjp), pjp.getArgs());
                value = redisCommandService.hGet(key, k, anno.classType());
                if(value == null){
                    Log.info("[info]"+key+"is not exists in cache");
                    //进入数据库中查询
                    value = pjp.proceed();
                    redisCommandService.hSet(key, k, value);
                    Log.info("[info]"+key+"has add to cache");
                }
            }
        }else if(cacheType == ReadCacheType.Maps){
            
        }else if(cacheType == ReadCacheType.String){
            if(fieldKey != null && "".equals("")){
                String k =  parseKey(fieldKey, getMethod(pjp), pjp.getArgs());
                value = redisCommandService.hGet(key, k, anno.classType());
                if(value == null){
                    Log.info("[info]"+key+"is not exists in cache");
                    //进入数据库中查询
                    value = pjp.proceed();
                    redisCommandService.hSet(key, k, value);
                    Log.info("[info]"+key+"has add to cache");
                }
            }
        }
        
        return value;
    }
    /**
     * 删除缓存
    *TODO:2016-10-13:下午5:35:48
    *return Object
     * @throws Throwable
     */
    @Around(DELETE)
    public Object delete(ProceedingJoinPoint pjp) throws Throwable{
        DeleteToRedis anno = getAnnotation(pjp,DeleteToRedis.class);
        String key = anno.key();
        String fieldKey = anno.fieldKey();
        Object obj = pjp.proceed();
        Long result = null;
        if(obj != null){
            fieldKey = parseKey(fieldKey, getMethod(pjp), pjp.getArgs());
            result = redisCommandService.hMapRemove(key, fieldKey);
        }
        return result;
    }
    
    /**
     * 更新缓存
    *TODO:2016-10-15:下午4:04:53
    *return Object
     * @param <T>
     * @throws Throwable
     * @throws SecurityException
     */
    public  Object update(ProceedingJoinPoint pjp) throws Throwable{
        UpdateToRedis anno = getAnnotation(pjp,UpdateToRedis.class);
        return updateRedis(anno,pjp);
    }
    private <T> Long updateRedis(UpdateToRedis anno,ProceedingJoinPoint pjp) throws Throwable{
        Object value = pjp.proceed();
        String key = anno.key();
        String m = anno.mapKeyMethodName();
        Object params = pjp.getArgs()[0];
        T t = (T)params;
        Class c =t.getClass();
        Method mthod = c.getMethod(m);
        String pk = mthod.invoke(t, null).toString();
        return redisCommandService.hSet(key, pk, value);
    }
    
    private void addRedisCache(String key,String fieldKey,Object value,int expireTime,ReadCacheType cacheType) throws Exception{
        if(cacheType == ReadCacheType.Map){
            redisCommandService.hSet(key, fieldKey, value);
        }
    }
    /**
     * 获取缓存中的key
    *TODO:2016-10-15:下午2:22:16
    *return String
     */
    private String parseKey(String key,Method method,Object[] args){
        String parseKey = null;
        LocalVariableTableParameterNameDiscoverer temp = new LocalVariableTableParameterNameDiscoverer();
        String[] params = temp.getParameterNames(method);
        HashMap<String, Object> map = new HashMap<String, Object>();
        int i = 0;
        for (String string : params) {
            map.put("#"+string, args[i]);
            i++;
        }
        parseKey = map.get(key).toString();
        return parseKey;
    }
    /**
     * 获取子类的method(实现类) 因为方法
    *TODO:2016-10-15:上午10:31:58
    *return void
     * @throws NoSuchMethodException
     * @throws SecurityException
     */
    private Method getMethod(ProceedingJoinPoint pjp) throws SecurityException, NoSuchMethodException{
        Method method = null;
        try {
            Object[] args = pjp.getArgs();
            Class[] argType = new Class[args.length];
            for (int i = 0; i < args.length; i++) {
                argType[i] = args[i].getClass();
            }
            method =  pjp.getTarget().getClass().getMethod(pjp.getSignature().getName(), argType);
        } catch (Exception e) {
            e.printStackTrace();
        }

        return method;
    }
    /**
     * 获取注解
    *TODO:2016-10-13:下午4:55:27
    *return void
     * @return
     */
    private <T extends Annotation> T getAnnotation(ProceedingJoinPoint jp,
            Class<T> clazz){
        MethodSignature joinPointObject = (MethodSignature) jp.getSignature();
        Method method = joinPointObject.getMethod();
        return method.getAnnotation(clazz);
    }
}

3.新建redis的接口类:IRedisCommandService

public interface IRedisCommandService {

    /**
     * 为一个key设置value值 并 设置有效时间
     * 成功返回ok
     * TODO: 2016-8-3:下午10:19:10
     */
    public String set(String key,Object value,int expire) throws Exception;
    
    /**
     * 更具key获取value值
     * TODO: 2016-8-3:下午10:26:11
     */
    public <T> T get(String key,Class<T> t) throws Exception;
    

    
    //-------------------set集合操作
    
    /**将一个或多个 member 元素加入到集合 key 当中,已经存在于集合的 member 元素将被忽略。
    假如 key 不存在,则创建一个只包含 member 元素作成员的集合。
    当 key 不是集合类型时,返回一个错误。
    返回添加的元素数量,重复的元素将被不记数量**/
    public Long sadd(String key,Object... member) throws Exception;
    
    /**
     * 移除集合 key 中的一个或多个 member 元素,不存在的 member 元素会被忽略。
     * 当 key 不是集合类型,返回一个错误。
     * 返回被成功移除的元素数量
     * **/
    public Long srem(String key,Object... member) throws Exception;
    
    /**
     * 返回集合中的所有元素
     * 不存在元素则返回空集合
     * TODO: 2016-8-3:下午10:47:35
     */
    public <T> Set<T> smemebers(String key,Class<T> t) throws Exception;
    
    /**
     * 根据 key 移除set集合
     *返回set map list 集合中被删除的数量个数
     * TODO: 2016-8-3:下午10:49:42
     */
    public Long sremove(String key) throws Exception;
    //--------------------map集合操作
    /**
     * 将哈希表 key 中的域 field 的值设为 value 。
     * 如果 key 不存在,一个新的哈希表被创建并进行 HSET 操作。
     * 如果域 field 已经存在于哈希表中,旧值将被覆盖。
     *成功返回 1 失败返回 0
     * TODO: 2016-8-3:下午10:53:38
     */
    //操作单个值
    public Long hSet(String key,String field,Object obj) throws Exception;
    /**
     * 值是list
    *TODO:2016-10-15:下午3:31:41
    *return void
     */
    public void hSetMapList(String key,String field,List<?> list)  throws Exception;
    
    public String getMapValue(String key,String fieldKey) throws Exception;
    
    public <T> T hGet(String key,String field,Class<T> t) throws Exception;
    
    public Long hMapRemove(String key,String fieldKey);
    ///list集合操作
}

实现,该接口类:RedisCommandServiceImpl

@Service("redisCommandServiceImpl")
public class RedisCommandServiceImpl implements IRedisCommandService {

 

    @Autowired
    private JedisCluster jedisCluster;
    @Override
    public String set(String key, Object value, int expire) throws Exception {
        // TODO Auto-generated method stub
        String result = jedisCluster.set(key, JSON.toJSONString(value));
        if(expire > 0 ){
            //设置有效时间
            jedisCluster.expire(key, expire);
        }
        return result;
    }

    @Override
    public <T> T get(String key, Class<T> t) throws Exception {
        String text = jedisCluster.get(key);
        return JSON.parseObject(text, t);
    }

    @Override
    public Long sadd(String key, Object... member) throws Exception {
        String[] item = new String[member.length];
        for (int i = 0;i<member.length;i++) {
            item[i] = JSON.toJSONString(member[i]);
        }
        return jedisCluster.sadd(key, item);
    }

    @Override
    public Long srem(String key, Object... member) throws Exception {
        String[] item = new String[member.length];
        for(int i=0;i<member.length;i++){
            item[i] = JSON.toJSONString(member[i]);
        }
        
        return jedisCluster.srem(key, item);
    }

    @Override
    public <T> Set<T> smemebers(String key, Class<T> t) throws Exception {
        
        Set<String> set = jedisCluster.smembers(key);
        Set<T> sSet = new HashSet<T>();
        Iterator<String> iterator = set.iterator();
        while(iterator.hasNext()){
            String text = iterator.next();
            sSet.add(JSON.parseObject(text, t));
        }
        return sSet;
    }

    @Override
    public Long sremove(String key) throws Exception {
        return jedisCluster.del(key);
    }

    @Override
    public Long hSet(String key, String field, Object obj) throws Exception {

        System.out.println(JSON.toJSONString(obj));
        return jedisCluster.hset(key, field, JSON.toJSONString(obj));
    }
    
    @Override
    public <T> T hGet(String key, String field, Class<T> t) throws Exception {
        List<String> list = null;
        try {
            list = jedisCluster.hmget(key, field);
            if(list != null){
                return JSON.parseObject(list.get(0), t);
            }
        } catch (Exception e) {
            throw e;
        }
        
        return null;
    }

    @Override
    public String getMapValue(String key, String fieldKey) throws Exception {
        String value = jedisCluster.hget(key, fieldKey);
        return value;
    }

    @Override
    public void hSetMapList(String key, String field, List<?> list)
            throws Exception {
         jedisCluster.hset(key, field, JSON.toJSONString(list));
        
    }

    @Override
    public Long hMapRemove(String key, String fieldKey) {
        return jedisCluster.hdel(key, fieldKey);
        
    }

}

3.新建测试的用户信息类:

public class User implements Serializable {

    /**描述**/
    private static final long serialVersionUID = 1L;
    private String userName;
    private String userPwd;

    public String getUserName() {
        return userName;
    }
    public void setUserName(String userName) {
        this.userName = userName;
    }
    public String getUserPwd() {
        return userPwd;
    }
    public void setUserPwd(String userPwd) {
        this.userPwd = userPwd;
    }

}

4.操作用户数据信息的接口类:

public interface IUserDao {
    
    /**
    * 用户增加
    *TODO:2016-8-8:下午2:20:41
    *@return Long
    *@author puxiao
    */
    public Long doCreateUser(User u) throws DaoException;
  
    /**
    * 查询用户信息
    *TODO:2016-8-8:下午2:23:48
    *@return  User
    *@author puxiao
    */
    public User getUser(Long userId) throws DaoException;
}

 

5.实现该接口:

@Repository
public class UserDaoImpl extends BaseSqlMapClientDao implements IUserDao{
    
    @AddToRedis(key=RedisBusinessConstant.KEY_BS_USER,cacheType=ReadCacheType.Map,classType=User.class, expireTime = 0)
    @Override
    public Long doCreateUser(User u) throws DaoException {
        Long s = insert("userInfoVO.doCreateUser", u);
        System.out.println("ssssssssss>>>>"+s);
        return s;
    }

    @GetFromRedis(key=RedisBusinessConstant.KEY_BS_USER,cacheType=ReadCacheType.Map,classType=User.class,fieldKey="#userId")
    @Override
    public User getUser(Long userId) throws DaoException {
        
        return null;
    }

}

6,编写junit测试类

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath*:applicationContext-db.xml","classpath*:applicationContext-redis.xml"})
public class TestDataSource {
    @Autowired
    private IUserService service;
    @Test
    public void testRedisCache(){
        //addUser();
        getUser();
    }
    
    /**
     * 缓存----测试增加用户
    *TODO:2016-10-17:下午4:39:36
    *return void
     */
    public void addUser(){
        User u = new User();
        u.setPdaPwd("admin");
        u.setSiteName("admin123");
        Long result = service.doCreateUser(u);
        System.out.println("result:"+result);
    }
    
    /**
     * 从缓存中获取用户信息 根据用户id去查询用户信息
    *TODO:2016-10-17:下午5:03:01
    *return void
     */
    public void getUser(){
        User userInfo = service.getUser(11517l);
        System.out.println(userInfo.getUserName());
        System.out.println(userInfo.getCreatedBy());
    }
}

启动测试:(1)增加用户

 控制台信息:

查询数据库改用户信息被成功添加进去:

我们再来redis中查询是否存在该信息,

 

 

可以看到的是该用户信息id为:11601的用户信息 ,是以json的格式存在的,

,从redis长获取该用户,可以看到的是控制台并没有发送sql语句,而取的是存在redis中的用户信息。

 

展开阅读全文
打赏
0
2 收藏
分享
加载中
更多评论
打赏
0 评论
2 收藏
0
分享
返回顶部
顶部