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

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)虽然已经自动配置,但是不灵活(第一没有序列化,第二泛型为不是我们想要的类型)
     *  所以自己实现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数据
代码解析如下
spring-boot-starter-data-redis RedisTemplate源码理解_第1张图片
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);
    }
    }
    

你可能感兴趣的:(spring,java,redis,spring,boot)