spring-boot-starter-data-redis RedisTemplate源码理解
2020-01-15 10:58
1696 查看
RedisTemplate源码理解
笔者使用的版本为:spring-data-redis-2.2.2.RELEASE.jar
原始redis操作实现步骤:
- 封装config
- 创建jedis池
- 获取jedis
- jedis操作
RedisTemplate也基本是按照这个步骤来实现的,只是将共有方法抽象出来
RedisTemplate的实现步骤:
- 创建RedisConfig类
- 创建JedisPoolConfig
- RedisConnectionFactory
- RedisTemplate
创建RedisConfig类
首先创建redis-config.properties文件:
# Redis数据库索引(默认为0) spring.redis.database=0 # Redis服务器地址 spring.redis.host=127.0.0.1 # Redis服务器连接端口 spring.redis.port=6379 # Redis服务器连接密码(默认为空) spring.redis.password=123456 # 连接池最大连接数(使用负值表示没有限制) spring.redis.pool.max-active=100 # 连接池最大阻塞等待时间(使用负值表示没有限制) spring.redis.pool.max-wait=10000 # 连接池中的最大空闲连接 spring.redis.pool.max-idle=8 # 连接池中的最小空闲连接 spring.redis.pool.min-idle=5 # 连接超时时间(毫秒) spring.redis.timeout=1000000 # 最大连接数 spring.redis.pool.max-total=200
创建RedisConfig类:
import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.PropertySource; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.connection.RedisStandaloneConfiguration; import org.springframework.data.redis.connection.jedis.JedisClientConfiguration; import org.springframework.data.redis.connection.jedis.JedisConnectionFactory; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer; import org.springframework.data.redis.serializer.StringRedisSerializer; import redis.clients.jedis.JedisPoolConfig; @Configuration @PropertySource(value = { "classpath:redis-config.properties" }) public class RedisConfig { /** * 连接池配置信息 * @return */ @Bean @ConfigurationProperties(prefix = "spring.redis.pool") public JedisPoolConfig jedisPoolConfig() { JedisPoolConfig config = new JedisPoolConfig(); return config; } /** * 2.创建RedisConnectionFactory:配置redis 链接信息 */ @Bean @ConfigurationProperties(prefix = "spring.redis") public RedisConnectionFactory redisConnectionFactory(JedisPoolConfig config) { RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration(); JedisClientConfiguration.JedisPoolingClientConfigurationBuilder jpcf = (JedisClientConfiguration.JedisPoolingClientConfigurationBuilder) JedisClientConfiguration .builder(); // 修改我们的连接池配置 jpcf.poolConfig(config); // 通过构造器来构造jedis客户端配置 JedisClientConfiguration jedisClientConfiguration = jpcf.build(); return new JedisConnectionFactory(redisStandaloneConfiguration); } /** * RedisTemplate(或StringRedisTemplate)虽然已经自动配置,但是不灵活(第一没有序列化,第二泛型为<Object, Object>不是我们想要的类型) * 所以自己实现RedisTemplate或StringRedisTemplate) */ @Bean(name = "redisTemplate") public RedisTemplate<String, Object> redisTemplate(JedisConnectionFactory factory) { RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>(); redisTemplate.setConnectionFactory(factory); setRedisTemplate(redisTemplate); redisTemplate.afterPropertiesSet(); return redisTemplate; } public void setRedisTemplate(RedisTemplate redisTemplate) { // JdkSerializationRedisSerializer jdkSerializationRedisSerializer = new JdkSerializationRedisSerializer(); GenericJackson2JsonRedisSerializer jackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer(); // 设置值(value)的序列化采用FastJsonRedisSerializer。 redisTemplate.setValueSerializer(jackson2JsonRedisSerializer); // redisTemplate.setHashValueSerializer(fastJsonRedisSerializer); // 设置键(key)的序列化采用StringRedisSerializer。 redisTemplate.setKeySerializer(new StringRedisSerializer()); redisTemplate.setHashKeySerializer(new StringRedisSerializer()); redisTemplate.afterPropertiesSet(); } }
创建RedisTest类,进行jedis操作
import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.data.redis.core.RedisTemplate; import javax.annotation.Resource; @SpringBootTest class DemoApplicationTests { @Test void contextLoads() { } @Resource RedisTemplate<String, Object> redisTemplate; @Test void testOne() { redisTemplate.opsForValue().set("name", "jack"); Boolean hasKey = redisTemplate.hasKey("name"); System.out.println(hasKey); } }
RedisTemplate源码分析
opsForValue()方法返回的是一个ValueOperations.java
作用:操作redis数据
代码解析如下
RedisTemplate.hasKey()方法,主要内容如下:
public Boolean hasKey(K key) { // 1.将对象类型的key转换为byte[]类型 final byte[] rawKey = rawKey(key); // 2.执行execute方法,主要是为了获取RedisConnection,真正执行在回调方法里 return execute(new RedisCallback<Boolean>() { public Boolean doInRedis(RedisConnection connection) { // 3.真正执行方法 return connection.exists(rawKey); } }, true); }
execute()方法内容如下:
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"); // 1.获取连接池工厂,即RedisConfig类中的RedisConnectionFactory bean RedisConnectionFactory factory = this.getRequiredConnectionFactory(); RedisConnection conn = null; Object var11; try { if (enableTransactionSupport) { // only bind resources in case of potential transaction synchronization conn = RedisConnectionUtils.bindConnection(factory, enableTransactionSupport); } else { // 2.获取连接 conn = RedisConnectionUtils.getConnection(factory); } boolean existingConnection = TransactionSynchronizationManager.hasResource(factory); RedisConnection connToUse = preProcessConnection(conn, existingConnection); boolean pipelineStatus = connToUse.isPipelined(); if (pipeline && !pipelineStatus) { connToUse.openPipeline(); } RedisConnection connToExpose = (exposeConnection ? connToUse : createRedisConnectionProxy(connToUse)); // 3.封装连接后,将连接传入回调函数,然后执行真正的操作 T result = action.doInRedis(connToExpose); // close pipeline if (pipeline && !pipelineStatus) { connToUse.closePipeline(); } // TODO: any other connection processing? return postProcessResult(result, connToUse, existingConnection); } finally { RedisConnectionUtils.releaseConnection(conn, factory); } }
下面对execute()方法逐步解析
- 获取连接池工厂
public class RedisAccessor implements InitializingBean {@Nullable private RedisConnectionFactory connectionFactory; ... @Nullable public RedisConnectionFactory getConnectionFactory() { return this.connectionFactory; }
获取工厂这一步,直接从RedisAccessor类中获取,RedisTemplate类继承了RedisAccessor - 获得连接
RedisConnectionUtils:public static RedisConnection doGetConnection(RedisConnectionFactory factory, boolean allowCreate, boolean bind, boolean enableTransactionSupport) { ... // 获得连接操作 RedisConnection conn = factory.getConnection(); ... return conn; }
具体实现在JedisConnectionFactory.getConnection()中:public RedisConnection getConnection() { if (cluster != null) { return getClusterConnection(); } Jedis jedis = fetchJedisConnector(); // 主要操作 JedisConnection connection = (usePool ? new JedisConnection(jedis, pool, dbIndex, clientName) : new JedisConnection(jedis, null, dbIndex, clientName)); connection.setConvertPipelineAndTxResults(convertPipelineAndTxResults); return postProcessConnection(connection); }
JedisConnection封装了Jedis、Pool等域 - 执行回调函数
redisTemplate.hasKey(key):public Boolean hasKey(K key) { // 1.将对象类型的key转换为byte[]类型 final byte[] rawKey = rawKey(key); // 2.执行execute方法,主要是为了获取RedisConnection,真正执行在回调方法里 return execute(new RedisCallback<Boolean>() { public Boolean doInRedis(RedisConnection connection) { // 3.真正执行方法 return connection.exists(rawKey); } }, true); }
真正执行的为connection.exists方法,具体实现类为JedisConnection,方法内容如下:public Boolean exists(byte[] key) { try { if (isPipelined()) { pipeline(new JedisResult(pipeline.exists(key))); return null; } if (isQueueing()) { transaction(new JedisResult(transaction.exists(key))); return null; } // 执行方法 return jedis.exists(key); } catch (Exception ex) { throw convertJedisAccessException(ex); } }
- 点赞 1
- 收藏
- 分享
- 文章举报
相关文章推荐
- Spring源码追踪1——doGetBean(为什么org.springframework.data.redis.core.RedisTemplate的实例可以注入为ListOperations)
- Spring源码追踪1——doGetBean(为什么org.springframework.data.redis.core.RedisTemplate的实例可以注入为ListOperations)
- Spring源码追踪1——doGetBean(为什么org.springframework.data.redis.core.RedisTemplate的实例可以注入为ListOperations)
- spring boot data RedisTemplate 序列化问题
- Springboot RedisTemplate 报No qualifying bean of type... 不能按类型装配注入
- spring-data-redis RedisTemplate操作
- spring-boot-starter-data-redis
- maven依赖里redis的依赖spring-boot-starter-data-redis和spring-boot-starter-redis有什么区别?
- Springboot+redis(Jedis和RedisTemplate)+CRUD
- Spring Boot整合集成StringRedisTemplate的简单记录
- 入门必备,深入理解Spring Redis Data,源码分析,RedisDesktopManager
- springBoot之RedisTemplate和StringRedisTemplate的区别
- Spring data redis-StringRedisTemplate 用法
- 关于springboot整合redis(使用RedisTemplate操作redis)
- spring-data-redis RedisTemplate 操作redis时发现存储在redis中的key不是设置的string值,前面还多出了许多类似\xac\xed\x00\x05t\x00这
- spring-boot-starter-data-redis 翻译官方文档 6.1 - 6.4
- SpringBoot整合redis集群并使用StringRedisTemplate和RedisTemplate简单操作Redis集群
- Redis:Jedis的封装类:RedisTemplate在Springboot中的使用
- spring-boot-starter-data-redis
- REDIS学习(4)spring boot redisTemplate 对REDIS的简单封装,以及对引用包的说明,以及对序列化的详细说明