Spring Data Redis 项目源码框架分析

fmms 12年前
     redis是由Salvatore Sanfilippo用C语言编写的一个缓存系统,与memcached相比,提供了更多的处理复杂数据结构的方法;性能也非常的突出。    <p></p>    <p> <span style="white-space:pre;"> </span>由于项目需要,自己简单地看了下spring新加入的模块 spring data redis,spring data redis对jedis, jredis, rjc等redis的java客户端接口进行了进一部的抽象,类似于jdbcTemplate的实现。具体spring配置方式如下:</p>    <pre class="brush:xml; toolbar: true; auto-links: false;"><?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"   xmlns:context="http://www.springframework.org/schema/context"    xsi:schemaLocation="    http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">   <bean id="connectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"   p:host-name="${redis.host}" p:port="${redis.port}" p:password="${redis.pass}"/>  <!-- Configurer that replaces ${...} placeholders with values from a properties file -->  <context:property-placeholder location="classpath:redis.properties"/>    <context:annotation-config />   <context:component-scan base-package="org.springframework.data.redis.samples"/>   <bean id="redisTemplate" class="org.springframework.data.redis.core.StringRedisTemplate"    p:connection-factory-ref="connectionFactory"/>   </beans></pre>    <p></p>    <p> connectionFactory功能类似于spring 数据库连接的datasource,提供对远程redis server的连接访问;  redisTemplate类似于SqlMapClientTemplate,提供对数据库访问的模板方法。 </p>    <p> </p>    <p>下面是spring data redis class diagram <img title="404e1c02-5c9b-3939-91fe-281f9b26222f.jpg" border="0" alt="404e1c02-5c9b-3939-91fe-281f9b26222f.jpg" src="https://simg.open-open.com/show/d018bab01cf7b76d09831b73981cef4a.jpg" width="700" height="525" /><br /> 结合下面的代码我们进行分析:</p>    <pre class="brush:java; toolbar: true; auto-links: false;">public class Example{  @autowired  private RedisTemplate<String,String> template;    public void addLink(String userId, URL url){   template.opsForList.leftPush(userId, url.toExternalForm);  } }</pre> spring data redis根据数据的类型进行了接口方法的拆分,如 ValueOperations,ListOperations,SetOperations,ZSetOperations。template调用 opsForList拿到具体的对哪种数据结构进行操作的对象,进而调用相应的操作方法。DefaultListOperations等对象使用回调函数的方法向redis server进行请求。     <pre class="brush:java; toolbar: true; auto-links: false;"> public Long leftPush(K key, V value) {   final byte[] rawKey = rawKey(key);   final byte[] rawValue = rawValue(value);   return execute(new RedisCallback<Long>() {        public Long doInRedis(RedisConnection connection) {     return connection.lPush(rawKey, rawValue);    }   }, true);  }</pre> 在RedisTemplate中,有一个重要的方法execute对connection进行预处理,包括是否使用pipeline,是否expose(暴露)connection等,对server进行请求后的返回结果进行后续的处理等。     <pre class="brush:java; toolbar: true; auto-links: false;"> /**   * Executes the given action object within a connection that can be exposed or not. Additionally, the connection   * can be pipelined. Note the results of the pipeline are discarded (making it suitable for write-only scenarios).   *    * @param <T> return type   * @param action callback object to execute   * @param exposeConnection whether to enforce exposure of the native Redis Connection to callback code   * @param pipeline whether to pipeline or not the connection for the execution    * @return object returned by the action   */  public <T> T execute(RedisCallback<T> action, boolean exposeConnection, boolean pipeline) {   Assert.notNull(action, "Callback object must not be null");    RedisConnectionFactory factory = getConnectionFactory();   //由spring中配置的JedisConnectionFactory创建连接    RedisConnection conn = RedisConnectionUtils.getConnection(factory);    boolean existingConnection = TransactionSynchronizationManager.hasResource(factory);   preProcessConnection(conn, existingConnection);    boolean pipelineStatus = conn.isPipelined();//判断是否打开pipeline    if (pipeline && !pipelineStatus) {    conn.openPipeline();   }    try {    RedisConnection connToExpose = (exposeConnection ? conn : createRedisConnectionProxy(conn));    T result = action.doInRedis(connToExpose);    // TODO: any other connection processing?    // 对后续结果进行处理,但postProcessResult还是直接返回result的,不知为何?     return postProcessResult(result, conn, existingConnection);   } finally {    try {     if (pipeline && !pipelineStatus) {      conn.closePipeline();     }    } finally {     RedisConnectionUtils.releaseConnection(conn, factory);    }   }  }</pre>    <p></p>    <p></p>