zoukankan      html  css  js  c++  java
  • 深入浅出Redis-Spring整合Redis

    概述:

       在之前的博客中,有提到过Redis 在服务端的一些相关知识,今天主要讲一下Java 整合Redis的相关内容。

       下面是Jedis 的相关依赖:

        

            <dependency>
                <groupId>redis.clients</groupId>
                <artifactId>jedis</artifactId>
                <version>2.5.1</version>
            </dependency>
    
            <!-- redis -->
            <dependency>
                <groupId>org.springframework.data</groupId>
                <artifactId>spring-data-redis</artifactId>
                <version>1.0.2.RELEASE</version>
            </dependency>

    1、Jedis 单机客户端

       首先我们了解一下,使用Jedis 连接我们的Redis 服务器:

    public static void main(String[] args) {
            String host = "127.0.0.1";
            int port = 6379;
            Jedis jedis = new Jedis(host,port,50000);
            jedis.set("name","jayce");
            String name = jedis.get("name");
            System.out.println(name);
            jedis.close();
    }

      我们先来看直观的运行结果:

     

     1.1 Jedis 构造函数: 

      我们先从Jedis 的构造函数开始说起,在Jedis的源码中,我们可以看到Jedis 提供以下几种构造函数:

      从上图中我们可以看到一个很重要的信息,Jedis 继承BinaryJedis,并且它的所有构造函数都采用了父类的构造函数: 

    //根据host 默认端口6379获取连接
    public Jedis(final String host) {
        super(host);
        }
    //根据host 与特定端口获取连接
        public Jedis(final String host, final int port) {
        super(host, port);
        }
    //根据host 与特定端口获取连接,并且设定key的生命周期
        public Jedis(final String host, final int port, final int timeout) {
        super(host, port, timeout);
        }
    //根据JedisShardInfo 配置信息,获取连接
        public Jedis(JedisShardInfo shardInfo) {
        super(shardInfo);
        }
    //根据特定URI 获取连接
        public Jedis(URI uri) {
        super(uri);
       }

       我们可以观察到父类BinaryJedis 的构造函数中,最终的目的是为了创建一个client,而这个client实质上是一个connection:

      

       

      因此,我们在创建一个Jedis 对象的过程中,创建了一个对服务器进行连接的Client,而接下来的相关操作,也是由这个client 进行操作。

     1.2 Jedis 的Get和Set:

        在调用Get和Set方法之前,我们需要创建一个连接,然后进行相应的操作,下述代码提供了设置字符串,和设置对象到Redis 中,需要注意的是,我们在将对象放到Redis 之前,需要将对象进行序列化,因此对象需要实现Serializable接口

    public static void main(String[] args) {
            String host = "127.0.0.1";
            int port = 6381;
            Jedis jedis = new Jedis(host, port);
            setString(jedis);
            setObject(jedis);
            jedis.close();
        }
    
        private static void setString(Jedis jedis) {
            jedis.set("name", "jayce");
            String name = jedis.get("name");
            System.out.println(name);
        }
    
    
        private static void setObject(Jedis jedis) {
            User user = new User();
            user.setId(1);
            user.setName("jayce");
            user.setPassword("kong");
            byte[] values = SerializeUtil.serialize(user);
            byte[] names = "user".getBytes();
            jedis.set(names, values);
            byte[] bytes = jedis.get("user".getBytes());
            User userCache = (User) SerializeUtil.unserialize(bytes);
            System.out.println(userCache);
    
        }

        我们在服务器中的Redis 中可以看到:

        数据已经缓存到了Redis 中。

        

        然后,我们再跟踪一下,Jedis 是如何将一个对象存到了服务器中的:

        第一步:Jedis 调用 set 方法,然后调用内部的client进行操作:

    public String set(final String key, String value) {
        checkIsInMulti();
        client.set(key, value);
        return client.getStatusCodeReply();
        }

       第二步:client 调用 SafeEncoder.encode(key) 方法,将字符串转换成二进制数组,再调用client 中的 set(byte[],byte[])方法:

    public void set(final String key, final String value) {
        set(SafeEncoder.encode(key), SafeEncoder.encode(value));
        }
    
    public void set(final byte[] key, final byte[] value) {
        sendCommand(Command.SET, key, value);
       }

       第三步:在调用父类Connection中的 sendCommand() 方法,最终将内容传到服务器中:

    protected Connection sendCommand(final Command cmd, final byte[]... args) {
        try {
            connect();
            Protocol.sendCommand(outputStream, cmd, args);
            pipelinedCommands++;
            return this;
        } catch (JedisConnectionException ex) {
            // Any other exceptions related to connection?
            broken = true;
            throw ex;
        }
        }

    2、Jedis 单机版整合Spring

        在Spring官网中,给出了这样得一个Demo:

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xmlns:p="http://www.springframework.org/schema/p"
      xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    
      <bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" p:host-name="server" p:port="6379" />
    
    </beans>

        这个配置文件比较直接的帮我们配置了 jedisConectionFactory ,我们需要做的是注入这个Bean 之后,在工厂里面获取到Connection,然后进行相应的操作。

        根据常用的场景,我们用到的比较多的是 Pool<Jedis>,因此,这里为大家分享的是JedisPool 的相关配置:

    <bean id="redisClient" class="redis.clients.jedis.JedisPool">
            <constructor-arg name="host" value="${redis.host}"/>
            <constructor-arg name="port" value="${redis.port}"/>
            <!--<constructor-arg name="poolConfig" ref="jedisPoolConfig"/>-->
        </bean>

        

          接下来我们研究一下,JedisPool 的源码,方便我们对配置文件的理解:

    public JedisPool(GenericObjectPoolConfig poolConfig, String host) {
            this(poolConfig, host, 6379, 2000, (String)null, 0, (String)null);
        }
    
        public JedisPool(String host, int port) {
            this(new GenericObjectPoolConfig(), host, port, 2000, (String)null, 0, (String)null);
        }
    
        public JedisPool(String host) {
            URI uri = URI.create(host);
            if(uri.getScheme() != null && uri.getScheme().equals("redis")) {
                String h = uri.getHost();
                int port = uri.getPort();
                String password = uri.getUserInfo().split(":", 2)[1];
                int database = Integer.parseInt(uri.getPath().split("/", 2)[1]);
                this.internalPool = new GenericObjectPool(new JedisFactory(h, port, 2000, password, database, (String)null), new GenericObjectPoolConfig());
            } else {
                this.internalPool = new GenericObjectPool(new JedisFactory(host, 6379, 2000, (String)null, 0, (String)null), new GenericObjectPoolConfig());
            }
    
        }
    
        public JedisPool(URI uri) {
            String h = uri.getHost();
            int port = uri.getPort();
            String password = uri.getUserInfo().split(":", 2)[1];
            int database = Integer.parseInt(uri.getPath().split("/", 2)[1]);
            this.internalPool = new GenericObjectPool(new JedisFactory(h, port, 2000, password, database, (String)null), new GenericObjectPoolConfig());
        }
    
        public JedisPool(GenericObjectPoolConfig poolConfig, String host, int port, int timeout, String password) {
            this(poolConfig, host, port, timeout, password, 0, (String)null);
        }
    
        public JedisPool(GenericObjectPoolConfig poolConfig, String host, int port) {
            this(poolConfig, host, port, 2000, (String)null, 0, (String)null);
        }
    
        public JedisPool(GenericObjectPoolConfig poolConfig, String host, int port, int timeout) {
            this(poolConfig, host, port, timeout, (String)null, 0, (String)null);
        }
    
        public JedisPool(GenericObjectPoolConfig poolConfig, String host, int port, int timeout, String password, int database) {
            this(poolConfig, host, port, timeout, password, database, (String)null);
        }
    
        public JedisPool(GenericObjectPoolConfig poolConfig, String host, int port, int timeout, String password, int database, String clientName) {
            super(poolConfig, new JedisFactory(host, port, timeout, password, database, clientName));
        }

        

        JedisPool 的构造函数与上述的Jedis 的构造函数很相似,这里比较特别的是 GenericObjectPoolConfig 这个配置类,这个类 是org.apache.commons.pool2 包下面的一个用来设置池的大小的类

        我们在配置application.xml文件的时候,可以自己配置对应的池大小,但是如果没有相应的配置文件的同学,推荐还是使用默认配置。

    public static void main(String[] args) {
            ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext-Redis.xml");
            Pool<Jedis> jedisPool = (Pool)applicationContext.getBean("redisClient");
            Jedis jedis = jedisPool.getResource();
            setString(jedis);
            setObject(jedis);
            jedisPool.returnResource(jedis);
        }
    
        private static void setString(Jedis jedis) {
            jedis.set("name", "jayce");
            String name = jedis.get("name");
            System.out.println(name);
        }
    
    
        private static void setObject(Jedis jedis) {
            User user = new User();
            user.setId(1);
            user.setName("jayce");
            user.setPassword("kong");
            byte[] values = SerializeUtil.serialize(user);
            byte[] names = "user".getBytes();
            jedis.set(names, values);
            byte[] bytes = jedis.get("user".getBytes());
            User userCache = (User) SerializeUtil.unserialize(bytes);
            System.out.println(userCache);
    
        }

        运行结果:

    jayce
    User{id=1, name='jayce', password='kong'}

    3、总结

        项目源码:https://github.com/jaycekon/Crawl-Page

        后面会继续总结,Spring 整合 Redis 集群~

  • 相关阅读:
    JS是单线程的吗?
    JQuery $ $.extend(),$.fn和$.fn.extend javaScript对象、DOM对象和jQuery对象及转换 工具方法(utility)
    JavaScript 操作符 变量
    WEB组件 开发 (未完成 413)
    CSS传统布局之布局模型
    JavaScript 作用域 匿名函数 模仿块级作用域(私有作用域)
    JQuery常用API 核心 效果 JQueryHTML 遍历 Event事件
    JavaScript 属性类型(数据属性 访问器属性)
    CSS居中问题:块级元素和行级元素在水平方向以及垂直方向的居中问题
    javascript 深入浅出 (未完成417)
  • 原文地址:https://www.cnblogs.com/jaycekon/p/6495039.html
Copyright © 2011-2022 走看看