1、概述

Jedis是redis官网推荐的redis java client,代码维护在github https://github.com/xetorthio/jedis

本质上Jedis帮我们封装了各种redis命令,提供了各种和redis命令相关的方法使用。Jedis的基本结构如下图1.1所示。

图1.1 Jedis 工作过程

可以看到Jedis通过socket和redis server通信,通过发送redis命令和参数,接收redis server的结果,从而实现redis client。

2、源码解析

按照Jedis源码分为两个层次分析,分别是:以Jedis为核心和以JedisPool为核心。

先看一下Jedis jar包的层次结构,如下图2.1所示,下面都是以 jedis-2.9.0 为例。

图2.1 Jedis Jar包层次结构

可以看到,Jedis Jar包结构简单,主要有两个package:redis.clients.jedis 和 redis.clients.util。jedis包下主要是和jedis相关的核心类,util包下是jedis会用到的各种工具类。需要注意的是:jedis依赖apache 的 commons-pool2 包。

2.1 Jedis

使用Jedis连接redis server的Java代码如下:

//连接本地的 Redis 服务
Jedis jedis = new Jedis("localhost", 6379);
jedis.set("key","val");

一行代码就能完成redis的连接,从而开始使用redis。

先看一下Jedis这个类图,如下图2.2所示。

图2.2 Jedis 类图

上图可以看到,Jedis类继承了1个类,实现了7个接口。实现了BinaryJedis类,该类主要用于处理二进制数据,Socket发送给redis server的数据是二进制的。分别实现了JedisCommands、MultiKeyCommands、BasicCommands、ScriptingCommands、SentinelCommands、AdvancedJedisCommands、ClusterCommands接口,从接口名上可以看到,这些接口都声明了不同场景下的redis命令方法。JedisCommands声明了常用的redis命令方法,包含redis五种数据接口的相关操作方法;MultiKeyCommands声明了常用的redis批量操作方法;BasicCommands声明了redis基本系统操作方法;ScriptingCommands声明了redis 相关脚本命令方法;SentinelCommands声明了redis在哨兵模式下的相关命令方法;ClusterCommands声明了redis集群模式下的相关命令方法;AdvancedJedisCommands声明了redis的一些高级命令方法,包含redis配置等。

下面来分析一下Jedis的代码,其代码如下:

public class Jedis extends BinaryJedis implements JedisCommands, MultiKeyCommands,
AdvancedJedisCommands, ScriptingCommands, BasicCommands, ClusterCommands, SentinelCommands { protected Pool<Jedis> dataSource = null;
// Jedis提供了很多不同的构造方法,提供了各种接入手段,方便开发
// Jedis本质上通过调用父类BinaryJedis的构造器来完成初始化操作
public Jedis() {
super();
} public Jedis(final String host) {
super(host);
} public Jedis(final String host, final int port) {
super(host, port);
} ... // 下面是redis各种命令的封装方法
// 本质上都是调用父类 BinaryJedis 中定义的 client 来完成各种操作
/**
* Set the string value as value of the key. The string can't be longer than 1073741824 bytes (1
* GB).
* <p>
* Time complexity: O(1)
* @param key
* @param value
* @return Status code reply
*/
public String set(final String key, String value) {
checkIsInMultiOrPipeline();
client.set(key, value);
return client.getStatusCodeReply();
} /**
* Set the string value as value of the key. The string can't be longer than 1073741824 bytes (1
* GB).
* @param key
* @param value
* @param nxxx NX|XX, NX -- Only set the key if it does not already exist. XX -- Only set the key
* if it already exist.
* @param expx EX|PX, expire time units: EX = seconds; PX = milliseconds
* @param time expire time in the units of <code>expx</code>
* @return Status code reply
*/
public String set(final String key, final String value, final String nxxx, final String expx,
final long time) {
checkIsInMultiOrPipeline();
client.set(key, value, nxxx, expx, time);
return client.getStatusCodeReply();
} ... }

从上面可以看到Jedis本质上通过父类BinaryJedis中定义的 client来完成各种redis操作。BinaryJedis的代码如下:

public class BinaryJedis implements BasicCommands, BinaryJedisCommands, MultiKeyBinaryCommands,
AdvancedBinaryJedisCommands, BinaryScriptingCommands, Closeable {
// 用于和redis通信的客户端实例
protected Client client = null;
protected Transaction transaction = null;
protected Pipeline pipeline = null; // BinaryJedis提供了许多构造方法,用于初始化,
// Jedis类也是通过调用父类BinaryJedis的构造方法完成初始化
// BinaryJedis构造方法中本质上是在初始化Clent实例
public BinaryJedis() {
client = new Client();
} public BinaryJedis(final String host) {
URI uri = URI.create(host);
if (uri.getScheme() != null && uri.getScheme().equals("redis")) {
initializeClientFromURI(uri);
} else {
client = new Client(host);
}
} public BinaryJedis(final String host, final int port) {
client = new Client(host, port);
} public BinaryJedis(final String host, final int port, final boolean ssl) {
client = new Client(host, port, ssl);
} public BinaryJedis(final String host, final int port, final boolean ssl,
final SSLSocketFactory sslSocketFactory, final SSLParameters sslParameters,
final HostnameVerifier hostnameVerifier) {
client = new Client(host, port, ssl, sslSocketFactory, sslParameters, hostnameVerifier);
} public BinaryJedis(final String host, final int port, final int timeout) {
client = new Client(host, port);
client.setConnectionTimeout(timeout);
client.setSoTimeout(timeout);
} public BinaryJedis(final String host, final int port, final int timeout, final boolean ssl) {
client = new Client(host, port, ssl);
client.setConnectionTimeout(timeout);
client.setSoTimeout(timeout);
} public BinaryJedis(final String host, final int port, final int timeout, final boolean ssl,
final SSLSocketFactory sslSocketFactory, final SSLParameters sslParameters,
final HostnameVerifier hostnameVerifier) {
client = new Client(host, port, ssl, sslSocketFactory, sslParameters, hostnameVerifier);
client.setConnectionTimeout(timeout);
client.setSoTimeout(timeout);
} public BinaryJedis(final String host, final int port, final int connectionTimeout,
final int soTimeout) {
client = new Client(host, port);
client.setConnectionTimeout(connectionTimeout);
client.setSoTimeout(soTimeout);
} public BinaryJedis(final String host, final int port, final int connectionTimeout,
final int soTimeout, final boolean ssl) {
client = new Client(host, port, ssl);
client.setConnectionTimeout(connectionTimeout);
client.setSoTimeout(soTimeout);
} ...
}

通过BinaryJedis代码可以看到,Jedis主要通过Client来完成具体redis操作,Client的代码如下:

public class Client extends BinaryClient implements Commands {

  // Client类的构造器调用了父类BinaryClient的构造器
public Client() {
super();
} public Client(final String host) {
super(host);
} public Client(final String host, final int port) {
super(host, port);
} public Client(final String host, final int port, final boolean ssl) {
super(host, port, ssl);
} public Client(final String host, final int port, final boolean ssl,
final SSLSocketFactory sslSocketFactory, final SSLParameters sslParameters,
final HostnameVerifier hostnameVerifier) {
super(host, port, ssl, sslSocketFactory, sslParameters, hostnameVerifier);
} // 封装了各种redis命令方法,本质上调用了父类BinaryClient中的对应方法
@Override
public void set(final String key, final String value) {
set(SafeEncoder.encode(key), SafeEncoder.encode(value));
} public void set(final String key, final String value, final String nxxx, final String expx,
final long time) {
set(SafeEncoder.encode(key), SafeEncoder.encode(value), SafeEncoder.encode(nxxx),
SafeEncoder.encode(expx), time);
} public void get(final String key) {
get(SafeEncoder.encode(key));
} public void exists(final String key) {
exists(SafeEncoder.encode(key));
} public void exists(final String... keys) {
final byte[][] bkeys = SafeEncoder.encodeMany(keys);
exists(bkeys);
} public void del(final String... keys) {
final byte[][] bkeys = new byte[keys.length][];
for (int i = 0; i < keys.length; i++) {
bkeys[i] = SafeEncoder.encode(keys[i]);
}
del(bkeys);
}
... }

从上可以看到,Client类定义了封装redis命令的方法,本质上调用的父类BinaryClient中的方法,BinaryClient代码如下:

public class BinaryClient extends Connection {
public enum LIST_POSITION {
BEFORE, AFTER;
public final byte[] raw; private LIST_POSITION() {
raw = SafeEncoder.encode(name());
}
} private boolean isInMulti; private String password; private long db; private boolean isInWatch; // Binary提供了各种构造器方法
public BinaryClient() {
super();
} public BinaryClient(final String host) {
super(host);
} public BinaryClient(final String host, final int port) {
super(host, port);
} public BinaryClient(final String host, final int port, final boolean ssl) {
super(host, port, ssl);
} public BinaryClient(final String host, final int port, final boolean ssl,
final SSLSocketFactory sslSocketFactory, final SSLParameters sslParameters,
final HostnameVerifier hostnameVerifier) {
super(host, port, ssl, sslSocketFactory, sslParameters, hostnameVerifier);
} public boolean isInMulti() {
return isInMulti;
} public boolean isInWatch() {
return isInWatch;
} private byte[][] joinParameters(byte[] first, byte[][] rest) {
byte[][] result = new byte[rest.length + 1][];
result[0] = first;
System.arraycopy(rest, 0, result, 1, rest.length);
return result;
} public void setPassword(final String password) {
this.password = password;
} public void setDb(long db) {
this.db = db;
} @Override
public void connect() {
if (!isConnected()) {
super.connect();
if (password != null) {
auth(password);
getStatusCodeReply();
}
if (db > 0) {
select(Long.valueOf(db).intValue());
getStatusCodeReply();
}
}
} // 所有的redis命令方法本质上调用的父类Connection中的sendCommand方法
public void ping() {
sendCommand(Command.PING);
} public void set(final byte[] key, final byte[] value) {
sendCommand(Command.SET, key, value);
} public void set(final byte[] key, final byte[] value, final byte[] nxxx, final byte[] expx,
final long time) {
sendCommand(Command.SET, key, value, nxxx, expx, toByteArray(time));
} public void get(final byte[] key) {
sendCommand(Command.GET, key);
} public void quit() {
db = 0;
sendCommand(QUIT);
} public void exists(final byte[]... key) {
sendCommand(EXISTS, key);
} ... }

上面可以看到,BinaryClient中的redis命令方法本质上调用的是父类Connection中的sendCommand方法,下面看一下Connection代码。

public class Connection implements Closeable {

  private static final byte[][] EMPTY_ARGS = new byte[0][];

  // redis server host & port
private String host = Protocol.DEFAULT_HOST;
private int port = Protocol.DEFAULT_PORT;
// 用于和redis server通信的socket
private Socket socket;
// 用于发送和接收数据的io流对象
private RedisOutputStream outputStream;
private RedisInputStream inputStream;
private int pipelinedCommands = 0;
private int connectionTimeout = Protocol.DEFAULT_TIMEOUT;
private int soTimeout = Protocol.DEFAULT_TIMEOUT;
private boolean broken = false;
private boolean ssl;
private SSLSocketFactory sslSocketFactory;
private SSLParameters sslParameters;
private HostnameVerifier hostnameVerifier; // Connection类提供了各种不同的构造方法
public Connection() {
} public Connection(final String host) {
this.host = host;
} public Connection(final String host, final int port) {
this.host = host;
this.port = port;
} public Connection(final String host, final int port, final boolean ssl) {
this.host = host;
this.port = port;
this.ssl = ssl;
} public Connection(final String host, final int port, final boolean ssl,
SSLSocketFactory sslSocketFactory, SSLParameters sslParameters,
HostnameVerifier hostnameVerifier) {
this.host = host;
this.port = port;
this.ssl = ssl;
this.sslSocketFactory = sslSocketFactory;
this.sslParameters = sslParameters;
this.hostnameVerifier = hostnameVerifier;
} public Socket getSocket() {
return socket;
} public int getConnectionTimeout() {
return connectionTimeout;
} public int getSoTimeout() {
return soTimeout;
} public void setConnectionTimeout(int connectionTimeout) {
this.connectionTimeout = connectionTimeout;
} public void setSoTimeout(int soTimeout) {
this.soTimeout = soTimeout;
} public void setTimeoutInfinite() {
try {
if (!isConnected()) {
connect();
}
socket.setSoTimeout(0);
} catch (SocketException ex) {
broken = true;
throw new JedisConnectionException(ex);
}
} public void rollbackTimeout() {
try {
socket.setSoTimeout(soTimeout);
} catch (SocketException ex) {
broken = true;
throw new JedisConnectionException(ex);
}
} // redis命令调用方法,本质上调用的都是sendCommand通用方法
protected Connection sendCommand(final Command cmd, final String... args) {
final byte[][] bargs = new byte[args.length][];
for (int i = 0; i < args.length; i++) {
bargs[i] = SafeEncoder.encode(args[i]);
}
return sendCommand(cmd, bargs);
} protected Connection sendCommand(final Command cmd) {
return sendCommand(cmd, EMPTY_ARGS);
} ... // 具体和redis通信,发送命令的方法
protected Connection sendCommand(final Command cmd, final byte[]... args) {
try {
// 1. 建立redis连接
connect();
// 2. 使用Protocol.sendCommand方法发送redis命令和参数
Protocol.sendCommand(outputStream, cmd, args);
pipelinedCommands++;
return this;
} catch (JedisConnectionException ex) {
/*
* When client send request which formed by invalid protocol, Redis send back error message
* before close connection. We try to read it to provide reason of failure.
*/
try {
String errorMessage = Protocol.readErrorLineIfPossible(inputStream);
if (errorMessage != null && errorMessage.length() > 0) {
ex = new JedisConnectionException(errorMessage, ex.getCause());
}
} catch (Exception e) {
/*
* Catch any IOException or JedisConnectionException occurred from InputStream#read and just
* ignore. This approach is safe because reading error message is optional and connection
* will eventually be closed.
*/
}
// Any other exceptions related to connection?
broken = true;
throw ex;
}
} ... // 和redis server 建立连接,本质上使用socket通信
public void connect() {
if (!isConnected()) {
try {
socket = new Socket();
// ->@wjw_add
socket.setReuseAddress(true);
socket.setKeepAlive(true); // Will monitor the TCP connection is
// valid
socket.setTcpNoDelay(true); // Socket buffer Whetherclosed, to
// ensure timely delivery of data
socket.setSoLinger(true, 0); // Control calls close () method,
// the underlying socket is closed
// immediately
// <-@wjw_add socket.connect(new InetSocketAddress(host, port), connectionTimeout);
socket.setSoTimeout(soTimeout); if (ssl) {
if (null == sslSocketFactory) {
sslSocketFactory = (SSLSocketFactory)SSLSocketFactory.getDefault();
}
socket = (SSLSocket) sslSocketFactory.createSocket(socket, host, port, true);
if (null != sslParameters) {
((SSLSocket) socket).setSSLParameters(sslParameters);
}
if ((null != hostnameVerifier) &&
(!hostnameVerifier.verify(host, ((SSLSocket) socket).getSession()))) {
String message = String.format(
"The connection to '%s' failed ssl/tls hostname verification.", host);
throw new JedisConnectionException(message);
}
}
// 获取socket连接的io流对象
outputStream = new RedisOutputStream(socket.getOutputStream());
inputStream = new RedisInputStream(socket.getInputStream());
} catch (IOException ex) {
broken = true;
throw new JedisConnectionException(ex);
}
}
} ... }

通过Connection代码可以看到,其调用了 Prototcol 的 sendCommand 方法来发送redis命令和参数。Protocol代码如下。

public final class Protocol {

  private static final String ASK_RESPONSE = "ASK";
private static final String MOVED_RESPONSE = "MOVED";
private static final String CLUSTERDOWN_RESPONSE = "CLUSTERDOWN";
private static final String BUSY_RESPONSE = "BUSY";
private static final String NOSCRIPT_RESPONSE = "NOSCRIPT"; // 默认主机号和端口号
public static final String DEFAULT_HOST = "localhost";
public static final int DEFAULT_PORT = 6379;
public static final int DEFAULT_SENTINEL_PORT = 26379;
public static final int DEFAULT_TIMEOUT = 2000;
public static final int DEFAULT_DATABASE = 0;
// 支持的编码格式
public static final String CHARSET = "UTF-8"; // 通用命令常量
public static final byte DOLLAR_BYTE = '$';
public static final byte ASTERISK_BYTE = '*';
public static final byte PLUS_BYTE = '+';
public static final byte MINUS_BYTE = '-';
public static final byte COLON_BYTE = ':'; public static final String SENTINEL_MASTERS = "masters";
public static final String SENTINEL_GET_MASTER_ADDR_BY_NAME = "get-master-addr-by-name";
public static final String SENTINEL_RESET = "reset";
public static final String SENTINEL_SLAVES = "slaves";
public static final String SENTINEL_FAILOVER = "failover";
public static final String SENTINEL_MONITOR = "monitor";
public static final String SENTINEL_REMOVE = "remove";
public static final String SENTINEL_SET = "set"; public static final String CLUSTER_NODES = "nodes";
public static final String CLUSTER_MEET = "meet";
public static final String CLUSTER_RESET = "reset";
public static final String CLUSTER_ADDSLOTS = "addslots";
public static final String CLUSTER_DELSLOTS = "delslots";
public static final String CLUSTER_INFO = "info";
public static final String CLUSTER_GETKEYSINSLOT = "getkeysinslot";
public static final String CLUSTER_SETSLOT = "setslot";
public static final String CLUSTER_SETSLOT_NODE = "node";
public static final String CLUSTER_SETSLOT_MIGRATING = "migrating";
public static final String CLUSTER_SETSLOT_IMPORTING = "importing";
public static final String CLUSTER_SETSLOT_STABLE = "stable";
public static final String CLUSTER_FORGET = "forget";
public static final String CLUSTER_FLUSHSLOT = "flushslots";
public static final String CLUSTER_KEYSLOT = "keyslot";
public static final String CLUSTER_COUNTKEYINSLOT = "countkeysinslot";
public static final String CLUSTER_SAVECONFIG = "saveconfig";
public static final String CLUSTER_REPLICATE = "replicate";
public static final String CLUSTER_SLAVES = "slaves";
public static final String CLUSTER_FAILOVER = "failover";
public static final String CLUSTER_SLOTS = "slots";
public static final String PUBSUB_CHANNELS = "channels";
public static final String PUBSUB_NUMSUB = "numsub";
public static final String PUBSUB_NUM_PAT = "numpat"; public static final byte[] BYTES_TRUE = toByteArray(1);
public static final byte[] BYTES_FALSE = toByteArray(0); private Protocol() {
// this prevent the class from instantiation
} public static void sendCommand(final RedisOutputStream os, final Command command,
final byte[]... args) {
sendCommand(os, command.raw, args);
} // 完成redis命令和数据的发送
private static void sendCommand(final RedisOutputStream os, final byte[] command,
final byte[]... args) {
try {
os.write(ASTERISK_BYTE);
os.writeIntCrLf(args.length + 1);
os.write(DOLLAR_BYTE);
os.writeIntCrLf(command.length);
os.write(command);
os.writeCrLf(); for (final byte[] arg : args) {
os.write(DOLLAR_BYTE);
os.writeIntCrLf(arg.length);
os.write(arg);
os.writeCrLf();
}
} catch (IOException e) {
throw new JedisConnectionException(e);
}
} ... }

Jedis中通过继承File的IO流程类定义了redis 操作的IO流,包含RedisOutputStream 和 RedisInputStream,用于定义redis的一些定制化操作。

通过上面的分析,举一个例子,比如:

jedis.set("key", "value") 本质上会给 redis server 发送字节流 *3\r\n$1\r\rnset\r\n$3\n\rkey\r\n$5\n\rvalue\r\n

下面来分析上面过程中的其他细节。

a. 字符串转字节数组

字节转数组工具类定义在 redis.clients.util 包下。

public final class SafeEncoder {
private SafeEncoder(){
throw new InstantiationError( "Must not instantiate this class" );
} public static byte[][] encodeMany(final String... strs) {
byte[][] many = new byte[strs.length][];
for (int i = 0; i < strs.length; i++) {
many[i] = encode(strs[i]);
}
return many;
} // 字符串编码为字节数组
public static byte[] encode(final String str) {
try {
if (str == null) {
throw new JedisDataException("value sent to redis cannot be null");
}
return str.getBytes(Protocol.CHARSET);
} catch (UnsupportedEncodingException e) {
throw new JedisException(e);
}
} public static String encode(final byte[] data) {
try {
return new String(data, Protocol.CHARSET);
} catch (UnsupportedEncodingException e) {
throw new JedisException(e);
}
}
}

从上面可以看到,通过调用JDK中的 getBytes 方法获取字节数组,同时指定编码格式UTF-8。

b. 命令定义

Jedis用到的所有redis命令和关键字都以枚举形式定义在Protocol类中,代码如下:

public final class Protocol {

    ...
// redis命令枚举
public static enum Command {
PING, SET, GET, QUIT, EXISTS, DEL, TYPE, FLUSHDB, KEYS, RANDOMKEY, RENAME, RENAMENX, RENAMEX, DBSIZE, EXPIRE, EXPIREAT, TTL, SELECT, MOVE, FLUSHALL, GETSET, MGET, SETNX, SETEX, MSET, MSETNX, DECRBY, DECR, INCRBY, INCR, APPEND, SUBSTR, HSET, HGET, HSETNX, HMSET, HMGET, HINCRBY, HEXISTS, HDEL, HLEN, HKEYS, HVALS, HGETALL, RPUSH, LPUSH, LLEN, LRANGE, LTRIM, LINDEX, LSET, LREM, LPOP, RPOP, RPOPLPUSH, SADD, SMEMBERS, SREM, SPOP, SMOVE, SCARD, SISMEMBER, SINTER, SINTERSTORE, SUNION, SUNIONSTORE, SDIFF, SDIFFSTORE, SRANDMEMBER, ZADD, ZRANGE, ZREM, ZINCRBY, ZRANK, ZREVRANK, ZREVRANGE, ZCARD, ZSCORE, MULTI, DISCARD, EXEC, WATCH, UNWATCH, SORT, BLPOP, BRPOP, AUTH, SUBSCRIBE, PUBLISH, UNSUBSCRIBE, PSUBSCRIBE, PUNSUBSCRIBE, PUBSUB, ZCOUNT, ZRANGEBYSCORE, ZREVRANGEBYSCORE, ZREMRANGEBYRANK, ZREMRANGEBYSCORE, ZUNIONSTORE, ZINTERSTORE, ZLEXCOUNT, ZRANGEBYLEX, ZREVRANGEBYLEX, ZREMRANGEBYLEX, SAVE, BGSAVE, BGREWRITEAOF, LASTSAVE, SHUTDOWN, INFO, MONITOR, SLAVEOF, CONFIG, STRLEN, SYNC, LPUSHX, PERSIST, RPUSHX, ECHO, LINSERT, DEBUG, BRPOPLPUSH, SETBIT, GETBIT, BITPOS, SETRANGE, GETRANGE, EVAL, EVALSHA, SCRIPT, SLOWLOG, OBJECT, BITCOUNT, BITOP, SENTINEL, DUMP, RESTORE, PEXPIRE, PEXPIREAT, PTTL, INCRBYFLOAT, PSETEX, CLIENT, TIME, MIGRATE, HINCRBYFLOAT, SCAN, HSCAN, SSCAN, ZSCAN, WAIT, CLUSTER, ASKING, PFADD, PFCOUNT, PFMERGE, READONLY, GEOADD, GEODIST, GEOHASH, GEOPOS, GEORADIUS, GEORADIUSBYMEMBER, BITFIELD; public final byte[] raw; Command() {
raw = SafeEncoder.encode(this.name());
} } // redis 关键字
public static enum Keyword {
AGGREGATE, ALPHA, ASC, BY, DESC, GET, LIMIT, MESSAGE, NO, NOSORT, PMESSAGE, PSUBSCRIBE, PUNSUBSCRIBE, OK, ONE, QUEUED, SET, STORE, SUBSCRIBE, UNSUBSCRIBE, WEIGHTS, WITHSCORES, RESETSTAT, RESET, FLUSH, EXISTS, LOAD, KILL, LEN, REFCOUNT, ENCODING, IDLETIME, AND, OR, XOR, NOT, GETNAME, SETNAME, LIST, MATCH, COUNT, PING, PONG;
public final byte[] raw; Keyword() {
raw = SafeEncoder.encode(this.name().toLowerCase(Locale.ENGLISH));
}
}
}

2.2. JedisPool

在第1部分中已经提到,Jedis依赖apache 的 commons-pool2 的jar包。jedis主要使用commons-pool2 来实现jedis连接池。下面分析一下jedis如何使用 commons-pool2 实现一个jedis连接池。下图3.1为连接池实现类图。

图3.1 JedisPool 实现类图

JedisPool实现了Pool类,Pool类是jedis中定义的一个工具类,该类中有类型为GenericObjectPool的成员变量,GenericObjectPool是apache commons-pool2中连接池的一种实现。GenericObjectPool构造器有两个入参,分别是连接池配置类 BaseObjectPoolConfig 和PooledObjectFactory 池中对象生成工厂类。Jedis针对apache commons-pool2 中的PooledObjectFactory实现了jedis的池内对象生成工厂类。池内对象生成工厂类生成的对象类型是PooledObject,其有实现类DefaultPooledObject。

对于GenericObjectPool的实现细节,后续写一篇解析一下。

再来看一下 GenericObjectPoolConfig 代码中的默认配置。

public class GenericObjectPoolConfig extends BaseObjectPoolConfig {

    ...

    /**
* The default value for the {@code maxTotal} configuration attribute.
* @see GenericObjectPool#getMaxTotal()
*/
// 默认最大池大小
public static final int DEFAULT_MAX_TOTAL = 8; /**
* The default value for the {@code maxIdle} configuration attribute.
* @see GenericObjectPool#getMaxIdle()
*/
// 默认池中最大空闲对象数
public static final int DEFAULT_MAX_IDLE = 8; /**
* The default value for the {@code minIdle} configuration attribute.
* @see GenericObjectPool#getMinIdle()
*/
// 默认池中最小空闲对象数
public static final int DEFAULT_MIN_IDLE = 0; private int maxTotal = DEFAULT_MAX_TOTAL; private int maxIdle = DEFAULT_MAX_IDLE; private int minIdle = DEFAULT_MIN_IDLE; ... }

3、 总结

通过上面的源码解析,基本了解了Jedis的工作原理。Jedis作为使用Java语言实现的Redis客户端,原理是通过socket 和 redis server通信,传输redis命令和参数。同时Jedis借助apache commons-pool2 实现了redis连接池。

最新文章

  1. Amoeba -- 阿里巴巴工程师的开源项目之一陈思儒
  2. Unity3D优化总结(一)
  3. FusionCharts简单教程(六)-----如何自定义图表上的工具提示
  4. 获取当前html标签自定义属性的值
  5. 【4_237】Delete Node in a Linked List
  6. CStringUtf8ToUnicode
  7. 1Web语言:开始了解HTML
  8. Oracle 将不同列的值拼接成一个 字符串
  9. Linux VM子系统参数调整
  10. Git命令参考手册(转)
  11. 使用GLSL实现更多数量的局部光照 【转】
  12. 求职,找工作,平台大PK
  13. MyEclipse使用经验总结
  14. AVFoundation--AVCaptureSession
  15. appium python andiroid自动化文档整理笔记
  16. 【python】Python的单例模式
  17. web中cookie的使用
  18. ADO.Net中DataSet的应用
  19. 64位平台C/C++容易犯的错误
  20. Android平台介绍

热门文章

  1. Linux上安装ElasticSearch及遇到的问题
  2. batch文件改修中遇到的sql问题
  3. 2019-11-29-Roslyn-打包自定义的文件到-NuGet-包
  4. 电脑系统win7和samba服务器连接不上解决办法
  5. AIX中的网络管理
  6. bootstrap-table.min.js不同版本返回分页参数不同的问题
  7. TDD之断言验证System.out.print输出
  8. Excel筛选操作
  9. JVM垃圾回收之CMS收集器
  10. mysql8.0.17复制搭建及其gtid的1062和1032异常