RedisTemplate源码分析

2,149 阅读4分钟

方法调用栈

write:771, AbstractChannelHandlerContext (io.netty.channel)
writeAndFlush:757, AbstractChannelHandlerContext (io.netty.channel)
writeAndFlush:812, AbstractChannelHandlerContext (io.netty.channel)
writeAndFlush:1036, DefaultChannelPipeline (io.netty.channel)
writeAndFlush:305, AbstractChannel (io.netty.channel) //lettuce的通信最底层是基于netty

channelWriteAndFlush:342, DefaultEndpoint (io.lettuce.core.protocol) //写数据到服务器
writeToChannelAndFlush:282, DefaultEndpoint (io.lettuce.core.protocol)
write:142, DefaultEndpoint (io.lettuce.core.protocol)
write:112, CommandExpiryWriter (io.lettuce.core.protocol)
dispatch:187, RedisChannelHandler (io.lettuce.core)
dispatch:152, StatefulRedisConnectionImpl (io.lettuce.core)
dispatch:467, AbstractRedisAsyncCommands (io.lettuce.core)

set:1203, AbstractRedisAsyncCommands (io.lettuce.core) //写数据
invoke0:-1, NativeMethodAccessorImpl (jdk.internal.reflect)
invoke:62, NativeMethodAccessorImpl (jdk.internal.reflect)
invoke:43, DelegatingMethodAccessorImpl (jdk.internal.reflect)
invoke:566, Method (java.lang.reflect)
handleInvocation:57, FutureSyncInvocationHandler (io.lettuce.core) 
invoke:80, AbstractInvocationHandler (io.lettuce.core.internal) //redis客户端-lettuce
set:-1, $Proxy67 (com.sun.proxy)
set:146, LettuceStringCommands (org.springframework.data.redis.connection.lettuce) //调用底层redis客户端
lettuce

set:274, DefaultedRedisConnection (org.springframework.data.redis.connection)
inRedis:240, DefaultValueOperations$3 (org.springframework.data.redis.core)
doInRedis:59, AbstractOperations$ValueDeserializingRedisCallback (org.springframework.data.redis.core)
execute:224, RedisTemplate (org.springframework.data.redis.core)
execute:184, RedisTemplate (org.springframework.data.redis.core)
execute:95, AbstractOperations (org.springframework.data.redis.core)
set:236, DefaultValueOperations (org.springframework.data.redis.core) //spring-data-redis

set:112, RedisUtil (com.example.redis.utils) //应用程序-工具类
getdata:28, TestController (com.example.redis.controller) //应用程序入口

invoke0:-1, NativeMethodAccessorImpl (jdk.internal.reflect)
invoke:62, NativeMethodAccessorImpl (jdk.internal.reflect)
invoke:43, DelegatingMethodAccessorImpl (jdk.internal.reflect)
invoke:566, Method (java.lang.reflect)
doInvoke:190, InvocableHandlerMethod (org.springframework.web.method.support)
invokeForRequest:138, InvocableHandlerMethod (org.springframework.web.method.support)
invokeAndHandle:104, ServletInvocableHandlerMethod (org.springframework.web.servlet.mvc.method.annotation)
invokeHandlerMethod:892, RequestMappingHandlerAdapter (org.springframework.web.servlet.mvc.method.annotation)
handleInternal:797, RequestMappingHandlerAdapter (org.springframework.web.servlet.mvc.method.annotation)
handle:87, AbstractHandlerMethodAdapter (org.springframework.web.servlet.mvc.method)
doDispatch:1039, DispatcherServlet (org.springframework.web.servlet)
doService:942, DispatcherServlet (org.springframework.web.servlet)
processRequest:1005, FrameworkServlet (org.springframework.web.servlet)
doGet:897, FrameworkServlet (org.springframework.web.servlet)
service:634, HttpServlet (javax.servlet.http)
service:882, FrameworkServlet (org.springframework.web.servlet)
service:741, HttpServlet (javax.servlet.http)
internalDoFilter:231, ApplicationFilterChain (org.apache.catalina.core)
doFilter:166, ApplicationFilterChain (org.apache.catalina.core)
doFilter:53, WsFilter (org.apache.tomcat.websocket.server)
internalDoFilter:193, ApplicationFilterChain (org.apache.catalina.core)
doFilter:166, ApplicationFilterChain (org.apache.catalina.core)
doFilterInternal:99, RequestContextFilter (org.springframework.web.filter)
doFilter:109, OncePerRequestFilter (org.springframework.web.filter)
internalDoFilter:193, ApplicationFilterChain (org.apache.catalina.core)
doFilter:166, ApplicationFilterChain (org.apache.catalina.core)
doFilterInternal:92, FormContentFilter (org.springframework.web.filter)
doFilter:109, OncePerRequestFilter (org.springframework.web.filter)
internalDoFilter:193, ApplicationFilterChain (org.apache.catalina.core)
doFilter:166, ApplicationFilterChain (org.apache.catalina.core)
doFilterInternal:93, HiddenHttpMethodFilter (org.springframework.web.filter)
doFilter:109, OncePerRequestFilter (org.springframework.web.filter)
internalDoFilter:193, ApplicationFilterChain (org.apache.catalina.core)
doFilter:166, ApplicationFilterChain (org.apache.catalina.core)
doFilterInternal:200, CharacterEncodingFilter (org.springframework.web.filter)
doFilter:109, OncePerRequestFilter (org.springframework.web.filter)
internalDoFilter:193, ApplicationFilterChain (org.apache.catalina.core)
doFilter:166, ApplicationFilterChain (org.apache.catalina.core)
invoke:202, StandardWrapperValve (org.apache.catalina.core)
invoke:96, StandardContextValve (org.apache.catalina.core)
invoke:490, AuthenticatorBase (org.apache.catalina.authenticator)
invoke:139, StandardHostValve (org.apache.catalina.core)
invoke:92, ErrorReportValve (org.apache.catalina.valves)
invoke:74, StandardEngineValve (org.apache.catalina.core)
service:343, CoyoteAdapter (org.apache.catalina.connector)
service:408, Http11Processor (org.apache.coyote.http11)
process:66, AbstractProcessorLight (org.apache.coyote)
process:853, AbstractProtocol$ConnectionHandler (org.apache.coyote)
doRun:1587, NioEndpoint$SocketProcessor (org.apache.tomcat.util.net)
run:49, SocketProcessorBase (org.apache.tomcat.util.net)
runWorker:1128, ThreadPoolExecutor (java.util.concurrent)
run:628, ThreadPoolExecutor$Worker (java.util.concurrent)
run:61, TaskThread$WrappingRunnable (org.apache.tomcat.util.threads)
run:834, Thread (java.lang)

应用程序入口

控制器

package com.example.redis.controller;

import com.example.redis.utils.RedisUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class TestController {
    @Autowired
    RedisUtil redisUtil;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;// 通过构造方法注入该对象

    @GetMapping("/getdata")
    public Object getdata(){
        //测试redis
        redisUtil.set("name","小猫"); //写数据
        System.out.println(redisUtil.getExpire("name")); //获取过期时间
        return redisUtil.get("name"); //读数据

    }
}


封装的工具类

主要是封装spring-data-redis的RedisTemplate

@Component //工具类本身也要变为spring的bean
public final class RedisUtil {

    @Resource
    private RedisTemplate<String, Object> redisTemplate; //往工具类注入RedisTemplate数据
    
/**
     * 普通缓存放入
     *
     * @param key   键
     * @param value 值
     * @return true成功 false失败
     */
    public boolean set(String key, Object value) {
        try {
            redisTemplate.opsForValue().set(key, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

/**
     * 普通缓存获取
     *
     * @param key 键
     * @return 值
     */
    public Object get(String key) {
        return key == null ? null : redisTemplate.opsForValue().get(key);
    }

声明bean-RedisTemplate

package com.example.redis.config;

import com.alibaba.fastjson.support.spring.FastJsonRedisSerializer;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;

@Configuration
@ConditionalOnClass(RedisOperations.class)
@EnableConfigurationProperties(RedisProperties.class)
public class RedisConfig {

    @Bean
    @ConditionalOnMissingBean(name = "redisTemplate") //基于注解方式声明bean-RedisTemplate
    public RedisTemplate<Object, Object> redisTemplate(
            RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<Object, Object> template = new RedisTemplate<>();
        FastJsonRedisSerializer fastJsonRedisSerializer = new FastJsonRedisSerializer(Object.class); //使用fastjson序列化
        // value值的序列化采用fastJsonRedisSerializer
        template.setValueSerializer(fastJsonRedisSerializer);
        template.setHashValueSerializer(fastJsonRedisSerializer);
        // key的序列化采用StringRedisSerializer
        template.setKeySerializer(new StringRedisSerializer());
        template.setHashKeySerializer(new StringRedisSerializer());
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }

    @Bean
    @ConditionalOnMissingBean(StringRedisTemplate.class)
    public StringRedisTemplate stringRedisTemplate(
            RedisConnectionFactory redisConnectionFactory) {
        StringRedisTemplate template = new StringRedisTemplate();
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }

}

核心作用
1.基于注解方式声明bean-RedisTemplate。
2.配置各种东西,比如key value用什么来序列化,这里的key是用自带的字符串序列化器来序列化,本质是在写读数据的时候,把key的字符串值和二进制值互相转换。value是用阿里的fastjson来序列化的,本质是在写读的时候,把value的对象值和二进制值互相转换。

spring-data-redis

class DefaultValueOperations<K, V> extends AbstractOperations<K, V> implements ValueOperations<K, V> {

public void set(K key, V value) {
    final byte[] rawValue = this.rawValue(value);
    this.execute(new AbstractOperations<K, V>.ValueDeserializingRedisCallback(key) {
      protected byte[] inRedis(byte[] rawKey, RedisConnection connection) {
        connection.set(rawKey, rawValue); //写数据
        return null;
      }
    }, true);
  }
public class RedisTemplate<K, V> extends RedisAccessor implements RedisOperations<K, V>, BeanClassLoaderAware {

abstract class AbstractOperations<K, V> {
@Nullable
  <T> T execute(RedisCallback<T> callback, boolean b) {
    return this.template.execute(callback, b);
  }
  
public class RedisTemplate<K, V> extends RedisAccessor implements RedisOperations<K, V>, BeanClassLoaderAware {

  @Nullable
  public <T> T execute(RedisCallback<T> action, boolean exposeConnection, boolean pipeline) {
    Assert.isTrue(this.initialized, "template not initialized; call afterPropertiesSet() before using it");
    Assert.notNull(action, "Callback object must not be null");
    RedisConnectionFactory factory = this.getRequiredConnectionFactory();
    RedisConnection conn = null;

    Object var11;
    try {
      if (this.enableTransactionSupport) {
        conn = RedisConnectionUtils.bindConnection(factory, this.enableTransactionSupport);
      } else {
        conn = RedisConnectionUtils.getConnection(factory);
      }

      boolean existingConnection = TransactionSynchronizationManager.hasResource(factory);
      RedisConnection connToUse = this.preProcessConnection(conn, existingConnection);
      boolean pipelineStatus = connToUse.isPipelined();
      if (pipeline && !pipelineStatus) {
        connToUse.openPipeline();
      }

      RedisConnection connToExpose = exposeConnection ? connToUse : this.createRedisConnectionProxy(connToUse);
      T result = action.doInRedis(connToExpose);
      if (pipeline && !pipelineStatus) {
        connToUse.closePipeline();
      }

      var11 = this.postProcessResult(result, connToUse, existingConnection);
    } finally {
      RedisConnectionUtils.releaseConnection(conn, factory);
    }

    return var11;
  }
public final V doInRedis(RedisConnection connection) {
      byte[] result = this.inRedis(AbstractOperations.this.rawKey(this.key), connection);
      return AbstractOperations.this.deserializeValue(result);
    }

DefaultedRedisConnection

public interface DefaultedRedisConnection extends RedisConnection {

/** @deprecated */
@Deprecated
default Boolean set(byte[] key, byte[] value) {
  return this.stringCommands().set(key, value); //1.获取命令 2.写数据
}

这一层是spring-data-redis,相当于是一个中介,再往下就是决定要使用具体的哪个redis客户端,是jedis?还是lettuce?


LettuceStringCommands

class LettuceStringCommands implements RedisStringCommands {

public Boolean set(byte[] key, byte[] value) {
  Assert.notNull(key, "Key must not be null!");
  Assert.notNull(value, "Value must not be null!");

  try {
    if (this.isPipelined()) {
      this.pipeline(this.connection.newLettuceResult(this.getAsyncConnection().set(key, value), Converters.stringToBooleanConverter()));
      return null;
    } else if (this.isQueueing()) {
      this.transaction(this.connection.newLettuceResult(this.getAsyncConnection().set(key, value), Converters.stringToBooleanConverter()));
      return null;
    } else {
      return Converters.stringToBoolean(this.getConnection().set(key, value)); //写数据
    }
  } catch (Exception var4) {
    throw this.convertLettuceAccessException(var4);
  }
}

具体的redis客户端是lettuce,因为springboot现在默认是lettuce。

redis客户端-lettuce

AbstractInvocationHandler

public final Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  if (args == null) {
    args = NO_ARGS;
  }

  if (args.length == 0 && method.getName().equals("hashCode")) {
    return this.hashCode();
  } else if (args.length == 1 && method.getName().equals("equals") && method.getParameterTypes()[0] == Object.class) {
    Object arg = args[0];
    if (arg == null) {
      return false;
    } else {
      return proxy == arg ? true : isProxyOfSameInterfaces(arg, proxy.getClass()) && this.equals(Proxy.getInvocationHandler(arg));
    }
  } else {
    return args.length == 0 && method.getName().equals("toString") ? this.toString() : this.handleInvocation(proxy, method, args); //调用
  }
}

FutureSyncInvocationHandler

protected Object handleInvocation(Object proxy, Method method, Object[] args) throws Throwable {
  try {
    Method targetMethod = this.translator.get(method);
    Object result = targetMethod.invoke(this.asyncApi, args); //调用
    if (result instanceof RedisFuture) {
      RedisFuture<?> command = (RedisFuture)result;
      if (isNonTxControlMethod(method.getName()) && isTransactionActive(this.connection)) {
        return null;
      } else {
        long timeout = this.getTimeoutNs(command);
        return LettuceFutures.awaitOrCancel(command, timeout, TimeUnit.NANOSECONDS);
      }
    } else {
      return result;
    }
  } catch (InvocationTargetException var9) {
    throw var9.getTargetException();
  }
}

到了命令这一层

public abstract class AbstractRedisAsyncCommands<K, V> implements RedisHashAsyncCommands<K, V>, RedisKeyAsyncCommands<K, V>, RedisStringAsyncCommands<K, V>, RedisListAsyncCommands<K, V>, RedisSetAsyncCommands<K, V>, RedisSortedSetAsyncCommands<K, V>, RedisScriptingAsyncCommands<K, V>, RedisServerAsyncCommands<K, V>, RedisHLLAsyncCommands<K, V>, BaseRedisAsyncCommands<K, V>, RedisTransactionalAsyncCommands<K, V>, RedisGeoAsyncCommands<K, V>, RedisClusterAsyncCommands<K, V> {

public <T> AsyncCommand<K, V, T> dispatch(RedisCommand<K, V, T> cmd) {
  AsyncCommand<K, V, T> asyncCommand = new AsyncCommand(cmd);
  RedisCommand<K, V, T> dispatched = this.connection.dispatch(asyncCommand); //
  return dispatched instanceof AsyncCommand ? (AsyncCommand)dispatched : asyncCommand;
}
public class StatefulRedisConnectionImpl<K, V> extends RedisChannelHandler<K, V> implements StatefulRedisConnection<K, V> {

public <T> RedisCommand<K, V, T> dispatch(RedisCommand<K, V, T> command) {
  RedisCommand toSend = this.preProcessCommand(command);

  RedisCommand var3;
  try {
    var3 = super.dispatch(toSend); //
  } finally {
    if (command.getType().name().equals(CommandType.MULTI.name())) {
      this.multi = this.multi == null ? new MultiOutput(this.codec) : this.multi;
    }

  }

  return var3;
}

public abstract class RedisChannelHandler<K, V> implements Closeable, ConnectionFacade {

protected <T> RedisCommand<K, V, T> dispatch(RedisCommand<K, V, T> cmd) {
  if (this.debugEnabled) {
    logger.debug("dispatching command {}", cmd);
  }

  if (this.tracingEnabled) {
    RedisCommand<K, V, T> commandToSend = cmd;
    TraceContextProvider provider = (TraceContextProvider)CommandWrapper.unwrap(cmd, TraceContextProvider.class);
    if (provider == null) {
      commandToSend = new TracedCommand(cmd, this.clientResources.tracing().initialTraceContextProvider().getTraceContext());
    }

    return this.channelWriter.write((RedisCommand)commandToSend); 
  } else {
    return this.channelWriter.write(cmd); //写数据
  }
}

public class CommandExpiryWriter implements RedisChannelWriter {

public <K, V, T> RedisCommand<K, V, T> write(RedisCommand<K, V, T> command) {
  this.potentiallyExpire(command, this.getExecutorService());
  return this.writer.write(command); //写数据
}
public class DefaultEndpoint implements RedisChannelWriter, Endpoint {

public <K, V, T> RedisCommand<K, V, T> write(RedisCommand<K, V, T> command) {
  LettuceAssert.notNull(command, "Command must not be null");

  try {
    this.sharedLock.incrementWriters();
    this.validateWrite(1);
    if (this.autoFlushCommands) {
      if (this.isConnected()) {
        this.writeToChannelAndFlush(command); //写数据
      } else {
        this.writeToDisconnectedBuffer(command);
      }
    } else {
      this.writeToBuffer(command);
    }
  } finally {
    this.sharedLock.decrementWriters();
    if (this.debugEnabled) {
      logger.debug("{} write() done", this.logPrefix());
    }

  }

  return command;
}

private ChannelFuture channelWriteAndFlush(RedisCommand<?, ?, ?> command) {
  if (this.debugEnabled) {
    logger.debug("{} write() writeAndFlush command {}", this.logPrefix(), command);
  }

  return this.channel.writeAndFlush(command); //写数据
}

netty

public abstract class AbstractChannel extends DefaultAttributeMap implements Channel {

public ChannelFuture writeAndFlush(Object msg) {
  return this.pipeline.writeAndFlush(msg); //写数据
}
abstract class AbstractChannelHandlerContext implements ChannelHandlerContext, ResourceLeakHint {

private void write(Object msg, boolean flush, ChannelPromise promise) {
  ObjectUtil.checkNotNull(msg, "msg");

  try {
    if (this.isNotValidPromise(promise, true)) {
      ReferenceCountUtil.release(msg);
      return;
    }
  } catch (RuntimeException var8) {
    ReferenceCountUtil.release(msg);
    throw var8;
  }

  AbstractChannelHandlerContext next = this.findContextOutbound(flush ? 98304 : '耀');
  Object m = this.pipeline.touch(msg, next);
  EventExecutor executor = next.executor();
  if (executor.inEventLoop()) {
    if (flush) {
      next.invokeWriteAndFlush(m, promise);
    } else {
      next.invokeWrite(m, promise);
    }
  } else {
    Object task;
    if (flush) {
      task = AbstractChannelHandlerContext.WriteAndFlushTask.newInstance(next, m, promise);
    } else {
      task = AbstractChannelHandlerContext.WriteTask.newInstance(next, m, promise);
    }

    if (!safeExecute(executor, (Runnable)task, promise, m)) {
      ((AbstractChannelHandlerContext.AbstractWriteTask)task).cancel();
    }
  }

}

作用

RedisTemplate的作用?为什么spring要封装为一个jar?
1.中介
用哪个redis客户端,jedis还是lettuce?springboot默认是lettuce,但是也可以配置为jedis。
2.配置各种东西
比如key value用哪个序列化器来序列化?

其实就是类似于spring的各种中介模板类,比如jdbc的模板类JDBCTemplate。

总结

set get,还有获取过期时间命令,流程都一样。

代码

github.com/13851809588…