Method call stack
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)
Copy the code
Application entry
The controller
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"," cat "); Println (redisutil.getexpire ("name")); // Write data system.out.println (redisutil.getexpire ("name")); Return redisUtil. Get ("name"); // Read data}}Copy the code
Encapsulated utility classes
The main package is the RedisTemplate of Spring-data-redis
Public Final class RedisUtil {@resource private RedisTemplate<String, Object> redisTemplate; // Add RedisTemplate data to the utility class /** * Add RedisTemplate data to the normal cache ** @param key * @param value * @return true success false failure */ public Boolean set(String key, Object value) { try { redisTemplate.opsForValue().set(key, value); return true; } catch (Exception e) { e.printStackTrace(); return false; Public Object get(String key) {return key == null? null : redisTemplate.opsForValue().get(key); }Copy the code
Bean – RedisTemplate declaration
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") // Declare bean-redistemplate public based on annotations RedisTemplate<Object, Object> redisTemplate( RedisConnectionFactory redisConnectionFactory) { RedisTemplate<Object, Object> template = new RedisTemplate<>(); FastJsonRedisSerializer fastJsonRedisSerializer = new FastJsonRedisSerializer(Object.class); / / use fastjson serialization / / the value of serialized using fastJsonRedisSerializer template. SetValueSerializer (fastJsonRedisSerializer); template.setHashValueSerializer(fastJsonRedisSerializer); / / key serialized using 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; }}Copy the code
1. Declare bean-redistemplate based on annotations. 2. Configure various things, such as how to serialize the key value. In this case, the key is serialized by the built-in string serializer. Value is serialized with Ali’s Fastjson. In essence, the object value of value and binary value are converted to each other during the writing and reading.
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); // Write data return null; } }, true); }Copy the code
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);
}
Copy the code
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; }Copy the code
public final V doInRedis(RedisConnection connection) {
byte[] result = this.inRedis(AbstractOperations.this.rawKey(this.key), connection);
return AbstractOperations.this.deserializeValue(result);
}
Copy the code
DefaultedRedisConnection
public interface DefaultedRedisConnection extends RedisConnection { /** @deprecated */ @Deprecated default Boolean set(byte[] key, byte[] value) { return this.stringCommands().set(key, value); //1. Get command 2. Write data}Copy the code
This layer is spring-data-Redis, which acts as a mediator, and then down below it is deciding which redis client to use, jedis? Or 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)); / / write data}} the catch (Exception var4) {throw this. ConvertLettuceAccessException (var4); }}Copy the code
The specific Redis client is lettuce, because Springboot is now the default.
Redis client -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); // call}}Copy the code
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); // call 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(); }}Copy the code
We’re at the command level
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;
}
Copy the code
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;
}
Copy the code
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); // Write data}}Copy the code
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); // Write data}Copy the code
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); / / write data} else {enclosing 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); // Write data}Copy the code
netty
public abstract class AbstractChannel extends DefaultAttributeMap implements Channel { public ChannelFuture writeAndFlush(Object msg) { return this.pipeline.writeAndFlush(msg); // Write data}Copy the code
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: 'yao '); 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(); }}}Copy the code
role
What does the RedisTemplate do? Why is Spring packaged as a JAR? 1. Which redis client should the mediation use, Jedis or lettuce? Springboot is lettuce by default, but can also be configured as jedis. 2. Configure various things such as which serializer to use for key values?
These are the various spring-like mediation template classes, such as the JDBC template class JDBCTemplate.
conclusion
Set get, get expiration time, same process.
code
Github.com/13851809588…