当前位置: 首页 > 工具软件 > CacheManager > 使用案例 >

自定义RedisCacheManager

潘泳
2023-12-01
  • 为什么要自定义RedisCacheManager
    CacheManager是对Cache进行管理,创建,获取,销毁等操作的,在创建Cache时,需要对其序列化,如下
public static RedisCacheConfiguration defaultCacheConfig(@Nullable ClassLoader classLoader) {

	DefaultFormattingConversionService conversionService = new DefaultFormattingConversionService();

	registerDefaultConverters(conversionService);

	return new RedisCacheConfiguration(Duration.ZERO, true, true, CacheKeyPrefix.simple(),
			SerializationPair.fromSerializer(RedisSerializer.string()),
			SerializationPair.fromSerializer(RedisSerializer.java(classLoader)), conversionService);
}

可以看到对value的序列化是SerializationPair.fromSerializer(RedisSerializer.java(classLoader)),我们继续追看RedisSerializer.java(classLoader)的返回值:

static RedisSerializer<Object> java(@Nullable ClassLoader classLoader) {
	return new JdkSerializationRedisSerializer(classLoader);
}

默认使用的是JDK的序列化机制,这就使得,我们存入redis中的数据类似于下面这样:

127.0.0.1:6379> get "emp::10001"
"\xac\xed\x00\x05sr\x00\x1acom.nl.cache.bean.Employee\x1f\x10\x81\"\xbd\xdc\x8c\x9c\x02\x00\x05L\x00\x03dIdt\x00\x13Ljava/lang/Integer;L\x00\x05emailt\x00\x12Ljava/lang/String;L\x00\x06genderq\x00~\x00\x01L\x00\x02idq\x00~\x00\x01L\x00\blastNameq\x00~\x00\x02xppt\x00\x0echo@unkown.comsr\x00\x11java.lang.Integer\x12\xe2\xa0\xa4\xf7\x81\x878\x02\x00\x01I\x00\x05valuexr\x00\x10java.lang.Number\x86\xac\x95\x1d\x0b\x94\xe0\x8b\x02\x00\x00xp\x00\x00\x00\x01sq\x00~\x00\x05\x00\x00'\x11t\x00\x03cho"

这让我们在存入数据后,想要比对时,不容易查看。所以我们决定,让以json的形式进行序列化。

  • 自定义CacheManager
    -注:springboot版本2.5.6
    我们参照org.springframework.data.redis.cache.RedisCacheManager的create()方法
public static RedisCacheManager create(RedisConnectionFactory connectionFactory) {

	Assert.notNull(connectionFactory, "ConnectionFactory must not be null!");

	return new RedisCacheManager(new DefaultRedisCacheWriter(connectionFactory),
			RedisCacheConfiguration.defaultCacheConfig());
}

我们只需修改RedisCacheManager构造方法的第二个参数RedisCacheConfiguration.defaultCacheConfig(),它的返回值是一个RedisCacheConfiguration类型,自然想到new一个就可以了,但发现它的构造方法是私有的,有两种方法,一种就是仿照这个类,写一个相同的类,把构造方法改为public,另一个就是通过反射的方式,鉴于再写一个类,冗余比较多,就决定用反射。
参考文章开头第一段代码,创建RedisCacheConfiguration

@Bean
  public RedisCacheManager customizedCacheManager(RedisConnectionFactory connectionFactory) throws InvocationTargetException, IllegalAccessException, InstantiationException {
  		//对 对象类型(employee)和string类型的序列化
       Jackson2JsonRedisSerializer<Employee> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Employee.class);
       Jackson2JsonRedisSerializer<String> keySerializer = new Jackson2JsonRedisSerializer<>(String.class);

       DefaultFormattingConversionService conversionService = new DefaultFormattingConversionService();
       RedisCacheConfiguration.registerDefaultConverters(conversionService);
       RedisCacheConfiguration redisCacheConfiguration = null;

       Constructor[] constructors = RedisCacheConfiguration.class.getDeclaredConstructors();
       for (Constructor constructor : constructors) {
           constructor.setAccessible(true);
           if(constructor.getParameterTypes().length==7){//因为只有构造方法,所以判断方式比较随意
               redisCacheConfiguration = (RedisCacheConfiguration) constructor.newInstance(Duration.ZERO, true, true, CacheKeyPrefix.simple(), RedisSerializationContext.SerializationPair.fromSerializer(keySerializer), RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer),conversionService);
           }
       }

       assert redisCacheConfiguration != null;
       //通过RedisCacheManagerBuilder来创建RedisCacheManager,也可以直接new
       return RedisCacheManager.RedisCacheManagerBuilder.fromConnectionFactory(connectionFactory).cacheDefaults(redisCacheConfiguration).build();
   }

将该组件注册到spring容器中即可。
这样,我们再次通过后台程序缓存写入redis中时,就可以看到下面的形式:

127.0.0.1:6379> keys *
1) "\"emp::10001\""
127.0.0.1:6379> get  "\"emp::10001\""
"{\"id\":10001,\"lastName\":\"cho\",\"email\":\"cho@unkown.com\",\"gender\":1,\"dId\":null}"
 类似资料: