RedisCacheManager 2.x 源码解析

2.X RedisCacheManager中没有RedisTemplate了,看起来更加复杂了,我们先弄清楚各个成员变量的含义,这样后面看源码的过程就会明了一些。

1. RedisCacheManager

里面的各个对象在2-5中详细解释。

public class RedisCacheManager extends AbstractTransactionSupportingCacheManager {
	// cacheWriter,实际对Redis进行读写,键值都是byte[]。
	private final RedisCacheWriter cacheWriter;
	
	// 默认的配置,包括ttl,序列化方式等。
	private final RedisCacheConfiguration defaultCacheConfig;
	
	// 所有预先定义好的Cache各自对应的配置(不预先定义好就等用到了再创建)。
	private final Map<String, RedisCacheConfiguration> initialCacheConfiguration;
	
	// 当Cache不存在时能否创建。
	private final boolean allowInFlightCacheCreation;
}

2. RedisCacheWriter

主要方法如下,可以看出就是跟RedisTemplate差不多的东西,但是只能操作byte[]。序列化和反序列化操作是在其它地方完成的,这个后面会说。

public interface RedisCacheWriter {
	void put(String name, byte[] key, byte[] value, @Nullable Duration ttl);
	byte[] get(String name, byte[] key);
	byte[] putIfAbsent(String name, byte[] key, byte[] value, @Nullable Duration ttl);
	void remove(String name, byte[] key);
	void clean(String name, byte[] pattern);
}

3. RedisCacheConfiguration

public class RedisCacheConfiguration {
	// 这四个是RedisCache的常规配置,就对应于CacheProperties.Redis中的那四个配置。
	private final Duration ttl;
	private final boolean cacheNullValues;
	private final CacheKeyPrefix keyPrefix;
	private final boolean usePrefix;
	
	// 这两个东西完成了序列化操作,每个Pair里面存了一个Reader和一个Writer,具体见4
	private final SerializationPair<String> keySerializationPair;
	private final SerializationPair<Object> valueSerializationPair;
	
	// 把object转成String,用于键的转换。
	private final ConversionService conversionService;
}

CacheProperties.Redis

@ConfigurationProperties(prefix = "spring.cache")
public class CacheProperties {
	public static class Redis {
		private Duration timeToLive;
		private boolean cacheNullValues = true;
		private String keyPrefix;
		private boolean useKeyPrefix = true;
	}
}

4. SerializationPair

它是RedisSerializationContext中的一个子接口,代码比较长,就看下面这一段。

interface SerializationPair<T> {

		static <T> SerializationPair<T> fromSerializer(RedisSerializer<T> serializer) {
			// serializer是序列化器,比如json序列化
			Assert.notNull(serializer, "RedisSerializer must not be null!");
			
			//RedisSerializerToSerializationPairAdapter的实现在下面
			return new RedisSerializerToSerializationPairAdapter<>(serializer);
		}
}
// # class RedisSerializerToSerializationPairAdapter<T>
protected RedisSerializerToSerializationPairAdapter(@Nullable RedisSerializer<T> serializer) {
		//看名字就能知道,这里创建了一个Reader,一个Writer,然后组成了一个pair 。读写过程中用的
		//序列化器就是传入的serializer。
		pair = new DefaultSerializationPair(new DefaultRedisElementReader<>(serializer),
				new DefaultRedisElementWriter<>(serializer));
}
// SerializationPair的实现,可以看到它就是由reader,writer组成的。
class DefaultSerializationPair<T> implements SerializationPair<T> {
	private final RedisElementReader<T> reader;
	private final RedisElementWriter<T> writer;
}
// RedisElementReader的实现,这里真正调用了serializer序列化操作。
// RedisElementWriter也差不多,只不过把read改成write。
class DefaultRedisElementReader<T> implements RedisElementReader<T> {
	private final @Nullable RedisSerializer<T> serializer;
	public T read(ByteBuffer buffer) {
		if (serializer == null) {
			return (T) buffer;
		}
		return serializer.deserialize(ByteUtils.extractBytes(buffer));
	}
}

5. RedisCache

CacheManager是管理Cache的,Cache才是实际进行读写的地方,看代码前可以想一下,读写过程中需要一个RedisCacheWriter,序列化器,string转换器,ttl等配置。这些东西CacheManager都已经准备好了。

public class RedisCache extends AbstractValueAdaptingCache {
	// Cache名
	private final String name;
	
	// 同CacheManager
	private final RedisCacheWriter cacheWriter;
	
	// 对应于这个Cache的配置,功能就是3,4中说的。
	private final RedisCacheConfiguration cacheConfig;
	
	// RedisCacheConfiguration中的conversionService。单独提取出来了而已。
	private final ConversionService conversionService;

6. 默认RedisManager创建的过程

  1. CacheAutoConfiguration通过CacheConfigurationImportSelector导入所有的ConfigurationClass。
		Map<CacheType, Class<?>> mappings = new EnumMap<>(CacheType.class);
		mappings.put(CacheType.GENERIC, GenericCacheConfiguration.class);
		mappings.put(CacheType.EHCACHE, EhCacheCacheConfiguration.class);
		mappings.put(CacheType.HAZELCAST, HazelcastCacheConfiguration.class);
		mappings.put(CacheType.INFINISPAN, InfinispanCacheConfiguration.class);
		mappings.put(CacheType.JCACHE, JCacheCacheConfiguration.class);
		mappings.put(CacheType.COUCHBASE, CouchbaseCacheConfiguration.class);
		mappings.put(CacheType.REDIS, RedisCacheConfiguration.class);
		mappings.put(CacheType.CAFFEINE, CaffeineCacheConfiguration.class);
		mappings.put(CacheType.SIMPLE, SimpleCacheConfiguration.class);
		mappings.put(CacheType.NONE, NoOpCacheConfiguration.class);
  1. 它是按从上到下的顺序来检索的,如果前面的创建成功了就不会创建后面的了。我们具体看RedisCacheConfiguration.class。
  2. 进入到RedisCacheConfiguration.class里面,下面的代码都注释了。
@Configuration
@ConditionalOnClass(RedisConnectionFactory.class)
@AutoConfigureAfter(RedisAutoConfiguration.class)
@ConditionalOnBean(RedisConnectionFactory.class)
@ConditionalOnMissingBean(CacheManager.class)
@Conditional(CacheCondition.class)
class RedisCacheConfiguration {
	// 缓存的配置信息,就是yaml中spring.cache开头的。具体到redis就是那四个。
	private final CacheProperties cacheProperties;
	
	// 定制化,这里其实没有用到。因为一个Customizer都没有。
	private final CacheManagerCustomizers customizerInvoker;
	
	// 解释在上面的3,4中,
	private final org.springframework.data.redis.cache.RedisCacheConfiguration redisCacheConfiguration;

	RedisCacheConfiguration(CacheProperties cacheProperties,
			CacheManagerCustomizers customizerInvoker,
			ObjectProvider<org.springframework.data.redis.cache.RedisCacheConfiguration> redisCacheConfiguration) {
		this.cacheProperties = cacheProperties;
		this.customizerInvoker = customizerInvoker;
		
		// redisCacheConfiguration.getIfAvailable()结果是null,具体的配置在最后那个determineConfiguration中。
		this.redisCacheConfiguration = redisCacheConfiguration.getIfAvailable();
	}

	@Bean
	public RedisCacheManager cacheManager(RedisConnectionFactory redisConnectionFactory,
			ResourceLoader resourceLoader) {
			// redisConnectionFactory是Redis处理连接,是Redis自己配置的。
			// builder是RedisCacheManager的构造器。
		RedisCacheManagerBuilder builder = RedisCacheManager
				// 配置连接信息
				.builder(redisConnectionFactory)
				// 配置 CacheManager中的defaultCacheConfig
				.cacheDefaults(determineConfiguration(resourceLoader.getClassLoader()));
				
		// 预先定义好的缓存名们,这些缓存会在CacheManger创建好后就创建出来,否则第一次要用到了才创建。
		List<String> cacheNames = this.cacheProperties.getCacheNames();
		if (!cacheNames.isEmpty()) {
			builder.initialCacheNames(new LinkedHashSet<>(cacheNames));
		}
		
		// 加入定制信息,这里实际没作用,相当于直接返回builder.build()。
		return this.customizerInvoker.customize(builder.build());
	}

	private org.springframework.data.redis.cache.RedisCacheConfiguration determineConfiguration(
			ClassLoader classLoader) {
		if (this.redisCacheConfiguration != null) {
			return this.redisCacheConfiguration;
		}
		
		// 获取redis相关的配置,ttl等4个配置信息。
		Redis redisProperties = this.cacheProperties.getRedis();
		
		// 获取默认的RedisCacheConfiguration。
		org.springframework.data.redis.cache.RedisCacheConfiguration config = org.springframework.data.redis.cache.RedisCacheConfiguration
				.defaultCacheConfig();
				
		// 设置序列化器。
		config = config.serializeValuesWith(SerializationPair
				.fromSerializer(new JdkSerializationRedisSerializer(classLoader)));
				
		// 后面就是设置redis相关的配置,ttl等4个配置信息
		if (redisProperties.getTimeToLive() != null) {
			config = config.entryTtl(redisProperties.getTimeToLive());
		}
		if (redisProperties.getKeyPrefix() != null) {
			config = config.prefixKeysWith(redisProperties.getKeyPrefix());
		}
		if (!redisProperties.isCacheNullValues()) {
			config = config.disableCachingNullValues();
		}
		if (!redisProperties.isUseKeyPrefix()) {
			config = config.disableKeyPrefix();
		}
		return config;
	}

}
  1. 现在RedisManager就生成了,接下去要创建预先定义好的那些Cache,这一步是通过Spring的afterPropertiesSet实现的。
public abstract class AbstractCacheManager implements CacheManager, InitializingBean {

	private final ConcurrentMap<String, Cache> cacheMap = new ConcurrentHashMap<>(16);

	private volatile Set<String> cacheNames = Collections.emptySet();
	
	// 这里去初始化预先定义好的Cache
	public void afterPropertiesSet() {
		initializeCaches();
	}

	public void initializeCaches() {
		// 调用抽象函数loadCaches。
		Collection<? extends Cache> caches = loadCaches();

		synchronized (this.cacheMap) {
			this.cacheNames = Collections.emptySet();
			this.cacheMap.clear();
			Set<String> cacheNames = new LinkedHashSet<>(caches.size());
			for (Cache cache : caches) {
				String name = cache.getName();
				this.cacheMap.put(name, decorateCache(cache));
				cacheNames.add(name);
			}
			this.cacheNames = Collections.unmodifiableSet(cacheNames);
		}
	}

	// 由RedisCacheManager具体实现。
	protected abstract Collection<? extends Cache> loadCaches();
}
// # RedisCacheManger
	protected Collection<RedisCache> loadCaches() {

		List<RedisCache> caches = new LinkedList<>();
		for (Map.Entry<String, RedisCacheConfiguration> entry : initialCacheConfiguration.entrySet()) {
			caches.add(createRedisCache(entry.getKey(), entry.getValue()));
		}
		return caches;
	}

7. 总结

RedisManager为RedisCache准备了RedisCacheWriter 和 RedisCacheConfiguration ,RedisCacheWriter完成了读写byte[],RedisCacheConfiguration中的SerializationPair完成了byte和object之间的转换,还存了Redis缓存用到的ttl等四个配置信息。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在Windows下安装Redis 6.x的过程如下: 1. 首先,打开Redis官方网站(https://redis.io/)并下载适用于Windows的Redis 6.x版本。 2. 解压缩下载的文件,并将解压后的文件夹重命名为“Redis”。 3. 在Redis文件夹找到redis.windows.conf文件并打开它。可以使用任何文本编辑器打开此文件。 4. 在redis.windows.conf文件,找到并修改以下属性: - 将bind属性的值改为“127.0.0.1”(如果只希望本地访问Redis),或者为“0.0.0.0”(如果希望允许外部访问Redis)。 - 将protected-mode属性的值改为“no”(如果要允许外部访问Redis)。 5. 保存并关闭redis.windows.conf文件。 6. 打开cmd命令提示符,导航到Redis文件夹的路径。 7. 在命令提示符,运行“redis-server.exe redis.windows.conf”命令以启动Redis服务器。如果一切正常,您将看到Redis成功启动并监听指定的IP地址和端口。 8. 如果需要在Windows服务安装Redis,请在管理员权限下打开cmd命令提示符,然后导航到Redis文件夹路径,并运行以下命令: "redis-server --service-install redis.windows.conf --loglevel verbose" 这将在Windows服务安装Redis。 9. 要启动Redis作为Windows服务,请在管理员权限下打开cmd命令提示符,并运行以下命令: "redis-server --service-start" 10. 至此,您已成功安装Redis 6.x并在Windows启动它。您可以使用Redis客户端连接到服务器并开始使用Redis的功能。 注意:在安装和配置Redis时,请确保您具有管理员权限,并且系统没有其他程序使用Redis所需的端口。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值