深入浅出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 集群~

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏我叫刘半仙

原自己手写一个Mybatis框架(简化)

       继上一篇手写SpringMVC之后,我最近趁热打铁,研究了一下Mybatis。MyBatis框架的核心功能其实不难,无非就是动态代理和jdbc的操...

7606
来自专栏SpringBoot 核心技术

第三十七章:基于SpringBoot架构以及参数装载完成接口安全认证

34710
来自专栏Spring相关

第2章—装配Bean—自动化装配Bean

CD和CDPlayer,如果你不将CD放入(注入)到播放器中,那么CD播放器其实是没多大用处的,所以说,CD播放器是依赖于CD才能完成它的使命.

472
来自专栏技术墨客

Spring核心——Bean的依赖注入 原

在设计模式与IoC这篇文章中,介绍了Spring基础的三大支柱的两项内容——IoC、Bean。本篇将继续围绕着Bean的创建时的注入方式来介绍Spring的核心...

651
来自专栏技术墨客

Spring核心——数据校验

在Java数据校验详解中详细介绍了Java数据校验相关的功能(简称Bean Validation,涵盖JSR-303、JSR-349、JSR-380),本文将在...

542
来自专栏xingoo, 一个梦想做发明家的程序员

【设计模式】—— 模板方法Template

  模式意图   定义一个类的框架,当它有不同的类时,再具体实现。   比如,我们设计一个跨系统的客户端软件,Windows需要一套展现类,Linux需要一套...

1868
来自专栏xdecode

Spring MVC核心技术

目录 异常处理 类型转换器 数据验证 文件上传与下载 拦截器 ----  异常处理 Spring MVC中, 系统的DAO, Service, Controll...

2877
来自专栏Java架构沉思录

聊聊设计模式之模板方法模式

导语 模板方法模式是指在父类中定义好算法的骨架,而把具体的算法步骤交给子类去实现的一种设计模式。模板方式模式可以在不改变算法整体骨架的情况下,对算法的某些步骤...

34811
来自专栏Java 技术分享

SpringMVC(二)

1033
来自专栏Spring相关

第11章—使用对象关系映射持久化数据—SpringBoot+SpringData+Jpa进行查询修改数据库

JPA由EJB 3.0软件专家组开发,作为JSR-220实现的一部分。但它又不限于EJB 3.0,你可以在Web应用、甚至桌面应用中使用。JPA的宗旨是为POJ...

683

扫描关注云+社区