分析「spring-data-redisのredistemplateの大きな穴を使用することを忘れた」
6417 ワード
先日spring-data-redisのソースコード(1.0.1-RELESE)をざっと見たばかりです
今日の朝、「spring-data-redisのredistemplateを使うのを忘れた大きな穴」を見ました.http://www.iteye.com/topic/1125295
またこの部分についてソースコードを分析し、以下のようにまとめた.
Spring-data-redisの各種Operations実装クラス,例えばRedisTemplate,DefaultSetOperations,DefaultListOperationsなど,Redisコマンドのクローズドは以下のような構造で呼び出される.
RedisTemplateのhasKey
戻りタイプを指定するRedisCallbackインタフェースを実装するには、関数doInRedisが1つしかありません.
doInRedisのパラメータはRedisConnectionインタフェースであり、spring-data-redisは非Redis Java Clientに対して対応するRedisConnectionを実現している.
JedisConnection
JredisConnection
RjcConnection
SrpConnection
目的は異なるClientのAPIを統一してアダプターと見なすことでしょう.
executeこれはテンプレート関数で、主に接続の問題を処理します.
Spring-data-redisは、非Redis Java Clientに対しても対応するRedisConnectionFactoryを実現し、接続を取得します.
例えばJedisConnectionFactory内部ではJedisPoolによる接続工場が実現されている.
executeテンプレート関数ソース:
通常、RedisCallbackでdoInRedisが取得したRedisConnectionは毎回新しい
「このtemplateが毎回新しい接続を生成する以上、このmultiとexecコマンドには卵があるのではないでしょうか. ”
RedisTemplateを使うと確かにこの質問がありますが、著者の公式回答に対する理解には違いがあります.
The methods are exposed in case the connection is shared across methods. Currently we don't provide any out of the box support for connection binding but the RedisTemplate supports it - just like with the rest of the templates, one connection could be bound to the running thread and the RT will use it without creating new ones.
回答ではRedisTemplateが接続バインドをサポートしていないことは確かに認められたが、後半では「他のテンプレートクラスでは、接続は現在のスレッドにバインドでき、RedisTemplateはこの接続を使用し、再作成しない」と述べた.
OK! 次にソースコードを分析し、このバインドがどのように実現されているかを見てみましょう.
org.springframework.data.redis.support.collections.AbstractRedisCollectionはspring-data-redis対redisのいくつかの集合型のデータ構造パッケージクラスの抽象クラスである
中にはrenameという関数があります
しかし、その実現は内部保有のRedisOperationsではなくCollectionUtilsである.では、このCollectionUtilsを見てみましょう.rename
このrenameはトランザクションによってrename操作が保証される場合、元のkeyは必ず存在する
これは静的関数であり,Redisに対する操作は伝達されたRedisOperationsによって達成される.
renameはRedisOperationsのexecuteを呼び出し、匿名のコールバックインタフェースに転送され、具体的な操作を実現します.これは前述したexecuteテンプレートと同じように見えます.しかし、ここのRedisOperationsはなぜwatchとmultiを使うことができますか?前にRedisTemplateは直接watchとmultiができないと言ったのではないでしょうか.(RedisOperationsはRedisTemplateのインタフェースであり、異なるデータ構造に対する操作クラスや集合はRedisTemplateから生成される、つまりRedisTemplateによってRedisが操作される)
実はこのexecuteテンプレートは前のものとは違いますが、ここのパラメータはSessionCallbackで、前のものはRedisCallbackです.名前から分かるように、この中のexecute呼び出しはセッション、つまり接続を維持しているのです.
ここのexecuteソースを見てください
あまり説明する必要はないでしょうが、SessionCallbackの実装を呼び出して具体的な操作を行う前後に、接続をバインドして解縛しました.
そしてセッションでexecuteでoperationsが呼び出されます.watch(key); 操作を待つと、これらの操作は前の分析のRedisTemplateのhasKeyの流れと同じで、前の分析のexecuteを呼び出して操作します.
前に戻ってソースコードを見て、そこのRedisConnectionはRedisConnectionUtilsで取りました.
接続バインド解除もRedisConnectionUtilsで行われています.ここではTransactionSynchronizationManagerで現在のスレッドに接続をバインドしています.springのDBトランザクション管理と同じです.ここでは詳しく分析しません(主にThreadLocalを使用します).
このような分析ではspring-data-redisはwatchとmultiを使用することができ,肝心なのはどのように使用するかの問題である.
まとめ:
RedisTemplateとその他の特定のタイプの操作クラスは、主に基本的な操作機能を実現しており、一部の高度な機能(上のrenameやRedisAtomicIntegerなどの高度な操作)もある.
SessionCallbackによって接続をバインドする操作クラスを取得することができ、その上の操作はすべて1つの接続にあり、高度な機能を実現することができます.
spring-data-redisでwatchとmultiを用いる、ソースコードのCollectionUtilsを参照することができる.rename
Spring-data-redisにも確かに問題があります.このブログを参照してください.http://ldd600.iteye.com/blog/1115196
私はプロジェクトの中で今でもJedisを直接使っています.そのソースコードはよく書けています.http://jimgreat.iteye.com/blog/1586671
今日の朝、「spring-data-redisのredistemplateを使うのを忘れた大きな穴」を見ました.http://www.iteye.com/topic/1125295
またこの部分についてソースコードを分析し、以下のようにまとめた.
Spring-data-redisの各種Operations実装クラス,例えばRedisTemplate,DefaultSetOperations,DefaultListOperationsなど,Redisコマンドのクローズドは以下のような構造で呼び出される.
RedisTemplateのhasKey
public Boolean hasKey(K key) {
final byte[] rawKey = rawKey(key);
return execute(new RedisCallback() {
public Boolean doInRedis(RedisConnection connection) {
return connection.exists(rawKey);
}
}, true);
}
戻りタイプを指定するRedisCallbackインタフェースを実装するには、関数doInRedisが1つしかありません.
doInRedisのパラメータはRedisConnectionインタフェースであり、spring-data-redisは非Redis Java Clientに対して対応するRedisConnectionを実現している.
JedisConnection
JredisConnection
RjcConnection
SrpConnection
目的は異なるClientのAPIを統一してアダプターと見なすことでしょう.
executeこれはテンプレート関数で、主に接続の問題を処理します.
Spring-data-redisは、非Redis Java Clientに対しても対応するRedisConnectionFactoryを実現し、接続を取得します.
例えばJedisConnectionFactory内部ではJedisPoolによる接続工場が実現されている.
executeテンプレート関数ソース:
public T execute(RedisCallback action, boolean exposeConnection, boolean pipeline) {
Assert.notNull(action, "Callback object must not be null");
RedisConnectionFactory factory = getConnectionFactory();
RedisConnection conn = RedisConnectionUtils.getConnection(factory);
boolean existingConnection = TransactionSynchronizationManager.hasResource(factory);
preProcessConnection(conn, existingConnection);
boolean pipelineStatus = conn.isPipelined();
if (pipeline && !pipelineStatus) {
conn.openPipeline();
}
try {
RedisConnection connToExpose = (exposeConnection ? conn : createRedisConnectionProxy(conn));
T result = action.doInRedis(connToExpose);
// close pipeline
if (pipeline && !pipelineStatus) {
conn.closePipeline();
}
// TODO: any other connection processing?
return postProcessResult(result, conn, existingConnection);
} finally {
RedisConnectionUtils.releaseConnection(conn, factory);
}
}
通常、RedisCallbackでdoInRedisが取得したRedisConnectionは毎回新しい
「このtemplateが毎回新しい接続を生成する以上、このmultiとexecコマンドには卵があるのではないでしょうか. ”
RedisTemplateを使うと確かにこの質問がありますが、著者の公式回答に対する理解には違いがあります.
The methods are exposed in case the connection is shared across methods. Currently we don't provide any out of the box support for connection binding but the RedisTemplate supports it - just like with the rest of the templates, one connection could be bound to the running thread and the RT will use it without creating new ones.
回答ではRedisTemplateが接続バインドをサポートしていないことは確かに認められたが、後半では「他のテンプレートクラスでは、接続は現在のスレッドにバインドでき、RedisTemplateはこの接続を使用し、再作成しない」と述べた.
OK! 次にソースコードを分析し、このバインドがどのように実現されているかを見てみましょう.
org.springframework.data.redis.support.collections.AbstractRedisCollectionはspring-data-redis対redisのいくつかの集合型のデータ構造パッケージクラスの抽象クラスである
中にはrenameという関数があります
public void rename(final String newKey) {
CollectionUtils.rename(key, newKey, operations);
key = newKey;
}
しかし、その実現は内部保有のRedisOperationsではなくCollectionUtilsである.では、このCollectionUtilsを見てみましょう.rename
このrenameはトランザクションによってrename操作が保証される場合、元のkeyは必ず存在する
static void rename(final K key, final K newKey, RedisOperations operations) {
operations.execute(new SessionCallback
これは静的関数であり,Redisに対する操作は伝達されたRedisOperationsによって達成される.
renameはRedisOperationsのexecuteを呼び出し、匿名のコールバックインタフェースに転送され、具体的な操作を実現します.これは前述したexecuteテンプレートと同じように見えます.しかし、ここのRedisOperationsはなぜwatchとmultiを使うことができますか?前にRedisTemplateは直接watchとmultiができないと言ったのではないでしょうか.(RedisOperationsはRedisTemplateのインタフェースであり、異なるデータ構造に対する操作クラスや集合はRedisTemplateから生成される、つまりRedisTemplateによってRedisが操作される)
実はこのexecuteテンプレートは前のものとは違いますが、ここのパラメータはSessionCallbackで、前のものはRedisCallbackです.名前から分かるように、この中のexecute呼び出しはセッション、つまり接続を維持しているのです.
ここのexecuteソースを見てください
public T execute(SessionCallback session) {
RedisConnectionFactory factory = getConnectionFactory();
// bind connection
RedisConnectionUtils.bindConnection(factory);
try {
return session.execute(this);
} finally {
RedisConnectionUtils.unbindConnection(factory);
}
}
あまり説明する必要はないでしょうが、SessionCallbackの実装を呼び出して具体的な操作を行う前後に、接続をバインドして解縛しました.
そしてセッションでexecuteでoperationsが呼び出されます.watch(key); 操作を待つと、これらの操作は前の分析のRedisTemplateのhasKeyの流れと同じで、前の分析のexecuteを呼び出して操作します.
前に戻ってソースコードを見て、そこのRedisConnectionはRedisConnectionUtilsで取りました.
RedisConnection conn = RedisConnectionUtils.getConnection(factory);
接続バインド解除もRedisConnectionUtilsで行われています.ここではTransactionSynchronizationManagerで現在のスレッドに接続をバインドしています.springのDBトランザクション管理と同じです.ここでは詳しく分析しません(主にThreadLocalを使用します).
このような分析ではspring-data-redisはwatchとmultiを使用することができ,肝心なのはどのように使用するかの問題である.
まとめ:
RedisTemplateとその他の特定のタイプの操作クラスは、主に基本的な操作機能を実現しており、一部の高度な機能(上のrenameやRedisAtomicIntegerなどの高度な操作)もある.
SessionCallbackによって接続をバインドする操作クラスを取得することができ、その上の操作はすべて1つの接続にあり、高度な機能を実現することができます.
spring-data-redisでwatchとmultiを用いる、ソースコードのCollectionUtilsを参照することができる.rename
Spring-data-redisにも確かに問題があります.このブログを参照してください.http://ldd600.iteye.com/blog/1115196
私はプロジェクトの中で今でもJedisを直接使っています.そのソースコードはよく書けています.http://jimgreat.iteye.com/blog/1586671