您的位置:首页 > 数据库 > Redis

spring-boot-starter-data-redis RedisTemplate源码理解

2020-01-15 10:58 1696 查看

RedisTemplate源码理解

笔者使用的版本为:spring-data-redis-2.2.2.RELEASE.jar

原始redis操作实现步骤:

  1. 封装config
  2. 创建jedis池
  3. 获取jedis
  4. jedis操作

RedisTemplate也基本是按照这个步骤来实现的,只是将共有方法抽象出来

RedisTemplate的实现步骤:

  1. 创建RedisConfig类
  2. 创建JedisPoolConfig
  3. RedisConnectionFactory
  4. 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()方法逐步解析

  1. 获取连接池工厂
    public class RedisAccessor implements InitializingBean {
    @Nullable
    private RedisConnectionFactory connectionFactory;
    ...
    @Nullable
    public RedisConnectionFactory getConnectionFactory() {
    return this.connectionFactory;
    }
    获取工厂这一步,直接从RedisAccessor类中获取,RedisTemplate类继承了RedisAccessor
  2. 获得连接
    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等域
  3. 执行回调函数
    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
  • 收藏
  • 分享
  • 文章举报
浮云心丶 发布了7 篇原创文章 · 获赞 3 · 访问量 163 私信 关注
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐