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连接池。

Jedis源码浅析的更多相关文章

  1. 【深入浅出jQuery】源码浅析--整体架构

    最近一直在研读 jQuery 源码,初看源码一头雾水毫无头绪,真正静下心来细看写的真是精妙,让你感叹代码之美. 其结构明晰,高内聚.低耦合,兼具优秀的性能与便利的扩展性,在浏览器的兼容性(功能缺陷.渐 ...

  2. 【深入浅出jQuery】源码浅析2--奇技淫巧

    最近一直在研读 jQuery 源码,初看源码一头雾水毫无头绪,真正静下心来细看写的真是精妙,让你感叹代码之美. 其结构明晰,高内聚.低耦合,兼具优秀的性能与便利的扩展性,在浏览器的兼容性(功能缺陷.渐 ...

  3. Struts2源码浅析-ConfigurationProvider

    ConfigurationProvider接口 主要完成struts配置文件 加载 注册过程 ConfigurationProvider接口定义 public interface Configurat ...

  4. (转)【深入浅出jQuery】源码浅析2--奇技淫巧

    [深入浅出jQuery]源码浅析2--奇技淫巧 http://www.cnblogs.com/coco1s/p/5303041.html

  5. HashSet其实就那么一回事儿之源码浅析

    上篇文章<HashMap其实就那么一回事儿之源码浅析>介绍了hashMap,  本次将带大家看看HashSet, HashSet其实就是基于HashMap实现, 因此,熟悉了HashMap ...

  6. Android 手势识别类 ( 三 ) GestureDetector 源码浅析

    前言:上 篇介绍了提供手势绘制的视图平台GestureOverlayView,但是在视图平台上绘制出的手势,是需要存储以及在必要的利用时加载取出手势.所 以,用户绘制出的一个完整的手势是需要一定的代码 ...

  7. Android开发之Theme、Style探索及源码浅析

    1 背景 前段时间群里有伙伴问到了关于Android开发中Theme与Style的问题,当然,这类东西在网上随便一搜一大把模板,所以关于怎么用的问题我想这里也就不做太多的说明了,我们这里把重点放在理解 ...

  8. 【深入浅出jQuery】源码浅析2--使用技巧

    最近一直在研读 jQuery 源码,初看源码一头雾水毫无头绪,真正静下心来细看写的真是精妙,让你感叹代码之美. 其结构明晰,高内聚.低耦合,兼具优秀的性能与便利的扩展性,在浏览器的兼容性(功能缺陷.渐 ...

  9. Android手势源码浅析-----手势绘制(GestureOverlayView)

    Android手势源码浅析-----手势绘制(GestureOverlayView)

随机推荐

  1. 万兴神剪手 Wondershare Filmora v9.2.11.6 简体中文版

    目录 1. 介绍 2. 简体中文9.2.1.10汉化版下载 3. 安装和激活说明 1. 介绍 万兴神剪手 Filmora 是一款界面简洁时尚.功能强大的视频编辑软件,它是深圳万兴科技公司近年来的代表作 ...

  2. linux centos中安装flash player

    本机为centos 7.0 64 1.用火狐浏览器随便打开一个视频网站,找到一个视频点进去,网站会提示未安装flash player.点击进去到adobe官网.2.下载flash player插件,可 ...

  3. AT&T推出云5G网络开源工具Airship

    导读 AT&T新推出的云5G网络依赖于一个名为“Airship”的开源供应工具,该工具在周一发布了第一个版本. AT&T负责网络云的副总裁Amy Wheelus告诉LightReadi ...

  4. zencart 显示Deprecated: Assigning the return value of new by reference is deprecated

    很多朋友的php程序当php的版本升级到5.3以后,会出现"Deprecated: Assigning the return value of new by reference is dep ...

  5. CSS中filter属性的使用

    filter 属性定义了元素的可视效果 blur 给图像设置高斯模糊."radius"一值设定高斯函数的标准差,或者是屏幕上以多少像素融在一起, 所以值越大越模糊. 如果没有设定值 ...

  6. pyqt5-QTDesigner--UI文件的使用方式

    方式一:直接加载UI文件 from PyQt5.QtWidgets import QApplication, QWidget import sys class win(QWidget): def __ ...

  7. 【NOIP2016提高A组五校联考2】running

    题目 小胡同学是个热爱运动的好孩子. 每天晚上,小胡都会去操场上跑步,学校的操场可以看成一个由n个格子排成的一个环形,格子按照顺时针顺序从0 到n- 1 标号. 小胡观察到有m 个同学在跑步,最开始每 ...

  8. less中的for循环

    .loop(@count) when (@counter > 0) {   .loop((@counter - 1));    // 递归调用自身   width: (10px * @count ...

  9. LTM加速优化特性

    TCP Express TCP Express 是 LTM 产品的一项重要特性. 借助 TCP Express,LTM 可分别为客户机端和服务器端创建独立的连接.这样一来,LTM 可以针对客户机连接和 ...

  10. Java面试题系列(七)锁的原理

    redis实现分布式锁 synchronized 和 reentrantlock的区别,偏向锁/轻量级锁/重量级锁的原理,能否从偏向锁直接升级成重量级锁