Home  >  Article  >  Database  >  How SpringBoot customizes Redis to implement cache serialization

How SpringBoot customizes Redis to implement cache serialization

WBOY
WBOYforward
2023-06-03 11:32:231039browse

1. Customized RedisTemplate

1.1. Redis API default serialization mechanism

The API-based Redis cache implementation uses the RedisTemplate template for data caching operations. Open the RedisTemplate class here to view Source code information of this class

public class RedisTemplate<K, V> extends RedisAccessor implements RedisOperations<K, V>, BeanClassLoaderAware {
    // 声明了key、value的各种序列化方式,初始值为空
    @Nullable
    private RedisSerializer keySerializer = null;
    @Nullable
    private RedisSerializer valueSerializer = null;
    @Nullable
    private RedisSerializer hashKeySerializer = null;
    @Nullable
    private RedisSerializer hashValueSerializer = null;
...
    // 进行默认序列化方式设置,设置为JDK序列化方式
    public void afterPropertiesSet() {
        super.afterPropertiesSet();
        boolean defaultUsed = false;
        if (this.defaultSerializer == null) {
            this.defaultSerializer = new JdkSerializationRedisSerializer(
                    this.classLoader != null ?
                            this.classLoader : this.getClass().getClassLoader());
        }
        ...
    }
        ...
}

As can be seen from the above RedisTemplate core source code, various serialization methods for cached data key and value are declared inside RedisTemplate, and the initial values ​​​​are empty; in the afterPropertiesSet() method , determine if the default serialization parameter defaultSerializer is empty, set the default serialization method of data to JdkSerializationRedisSerializer

According to the analysis of the above source code information, the following two important conclusions can be drawn:

(1) When using RedisTemplate for Redis data caching operations, the internal default serialization method is JdkSerializationRedisSerializer, so the entity class for data caching must implement the JDK's own serialization interface (such as Serializable);

( 2) When using RedisTemplate to perform Redis data caching operations, if the cache serialization method defaultSerializer is customized, the customized serialization method will be used.

In addition, in the RedisTemplate class source code, the various serialization types of cached data keys and values ​​seen are RedisSerializer. Enter the RedisSerializer source code to view the serialization methods supported by RedisSerializer (after entering the class, use Ctrl Alt and left-click the class name to view)

How SpringBoot customizes Redis to implement cache serialization

It can be seen that RedisSerializer is a Redis The serialization interface has 6 implementation classes by default. These 6 implementation classes represent 6 different data serialization methods. Among them, JdkSerializationRedisSerializer comes with JDK and is also the default data serialization method used within RedisTemplate. Developers can choose other supported serialization methods (such as JSON method) as needed.

1.2. Customized RedisTemplate serialization Mechanism

After introducing Redis dependency into the project, the RedisAutoConfiguration automatic configuration provided by Spring Boot will take effect. Open the RedisAutoConfiguration class and view the definition of RedisTemplate in the internal source code

public class RedisAutoConfiguration {
    @Bean
    @ConditionalOnMissingBean(
            name = {"redisTemplate"}
    )
    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
        RedisTemplate<Object, Object> template = new RedisTemplate();
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }
...
}

As can be seen from the above RedisAutoConfiguration core source code, in the Redis automatic configuration class, a RedisTemplate is initialized through the Redis connection factory RedisConnectionFactory; above the class The @ConditionalOnMissingBean annotation (as the name suggests, takes effect when a Bean does not exist) is added to indicate that if the developer customizes a Bean named redisTemplate, the default initialized RedisTemplate will not take effect.

If you want to use RedisTemplate with a custom serialization method for data caching operations, you can refer to the above core code to create a Bean component named redisTemplate and set the corresponding serialization method in the component

Next, create a package named com.lagou.config in the project, create a Redis custom configuration class RedisConfig under the package, and customize the Bean component named redisTemplate according to the above ideas

@Configuration
public class RedisConfig {
    // 自定义RedisTemplate
    @Bean
    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<Object, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(redisConnectionFactory);
        // 创建一个JSON格式序列化对象,对缓存数据的key和value进行转换
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        // 解决查询缓存转换异常的问题
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);
        // 设置RedisTemplate模板api序列化方式为json
        template.setDefaultSerializer(jackson2JsonRedisSerializer);
        return template;
    }
}

defines a RedisConfig configuration class through the @Configuration annotation, and uses the @Bean annotation to inject a redisTemplate component with the default name of the method name (note that the Bean component name must be redisTemplate). In the defined Bean component, a RedisTemplate is customized, using the customized Jackson2JsonRedisSerializer data serialization method; in the customized serialization method, an ObjectMapper is defined for data conversion settings

1.3, effect testing

How SpringBoot customizes Redis to implement cache serialization

It can be seen that executing the findById() method correctly queries the user comment information Comment, and repeats the same query operation. The database only executes the SQL statement once, which shows that the customization The Redis cache takes effect.

Use the Redis client visual management tool Redis Desktop Manager to view the cached data:

How SpringBoot customizes Redis to implement cache serialization

Execute the findById() method to query the user comment information and the Comment is correctly stored in Redis In the cache library, and the data cached to the Redis service has been stored and displayed in JSON format, it is also very convenient to view and manage, indicating that the customized Redis API template tool RedisTemplate takes effect

2. Customized RedisCacheManager

We have just improved the custom serialization method for the API-based RedisTemplate, thus realizing the JSON serialization method to cache data. However, this custom RedisTemplate has no effect on the annotation-based Redis cache. .

Next, we will explain the annotation-based Redis caching mechanism and custom serialization method

2.1. Redis annotation default serialization mechanism

Open Spring Boot to integrate Redis components The provided cache automatic configuration class RedisCacheConfiguration (under the org.springframework.boot.autoconfigure.cache package), view the source code information of this class, its core code is as follows

@Configuration
class RedisCacheConfiguration {
    @Bean
    public RedisCacheManager cacheManager(RedisConnectionFactory redisConnectionFactory, ResourceLoader resourceLoader) {
        RedisCacheManagerBuilder builder = RedisCacheManager
                .builder(redisConnectionFactory)
                .cacheDefaults(this.determineConfiguration(resourceLoader.getClassLoader()));
        List<String> cacheNames = this.cacheProperties.getCacheNames();
        if (!cacheNames.isEmpty()) {
            builder.initialCacheNames(new LinkedHashSet(cacheNames));
        }
        return (RedisCacheManager) this.customizerInvoker.customize(builder.build());
    }
    private org.springframework.data.redis.cache.RedisCacheConfiguration
    determineConfiguration(ClassLoader classLoader) {
        if (this.redisCacheConfiguration != null) {
            return this.redisCacheConfiguration;
        } else {
            Redis redisProperties = this.cacheProperties.getRedis();
            org.springframework.data.redis.cache.RedisCacheConfiguration config = org.springframework.data.redis.cache.RedisCacheConfiguration.defaultCacheConfig();
            config = config.serializeValuesWith(SerializationPair.fromSerializer(
                            new JdkSerializationRedisSerializer(classLoader)));
            ...
            return config;
        }
    }
}

从上述核心源码中可以看出,同RedisTemplate核心源码类似,RedisCacheConfiguration内部同样通过Redis连接工厂RedisConnectionFactory定义了一个缓存管理器RedisCacheManager;同时定制RedisCacheManager时,也默认使用了JdkSerializationRedisSerializer序列化方式。

如果想要使用自定义序列化方式的RedisCacheManager进行数据缓存操作,可以参考上述核心代码创建一个名为cacheManager的Bean组件,并在该组件中设置对应的序列化方式即可

在Spring Boot 2.X版本中,RedisCacheManager是独立构建的。因此,在SpringBoot 2.X版本中,对RedisTemplate进行自定义序列化机制构建后,仍然无法对RedisCacheManager内部默认序列化机制进行覆盖(这也就解释了基 于注解的Redis缓存实现仍然会使用JDK默认序列化机制的原因),想要基于注解的Redis缓存实现也使用自定义序列化机制,需要自定义RedisCacheManager

2.2、自定义RedisCacheManager

在项目的Redis配置类RedisConfig中,按照上一步分析的定制方法自定义名为cacheManager的Bean组件

    @Bean
    public RedisCacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
        // 分别创建String和JSON格式序列化对象,对缓存数据key和value进行转换
        RedisSerializer<String> strSerializer = new StringRedisSerializer();
        Jackson2JsonRedisSerializer jacksonSerial = new Jackson2JsonRedisSerializer(Object.class);
        // 解决查询缓存转换异常的问题
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        // om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY); // 上面注释过时代码的替代方法
        jacksonSerial.setObjectMapper(om);
        // 定制缓存数据序列化方式及时效
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
                .entryTtl(Duration.ofDays(1)) // 设置缓存数据的时效(设置为了1天)
                .serializeKeysWith(RedisSerializationContext.SerializationPair
                        .fromSerializer(strSerializer)) // 对当前对象的key使用strSerializer这个序列化对象,进行转换
                .serializeValuesWith(RedisSerializationContext.SerializationPair
                        .fromSerializer(jacksonSerial)) // 对value使用jacksonSerial这个序列化对象,进行转换
                .disableCachingNullValues();
        RedisCacheManager cacheManager = RedisCacheManager
                .builder(redisConnectionFactory).cacheDefaults(config).build();
        return cacheManager;
    }

上述代码中,在RedisConfig配置类中使用@Bean注解注入了一个默认名称为方法名的cacheManager组件。在定义的Bean组件中,通过RedisCacheConfiguration对缓存数据的key和value分别进行了序列化方式的定制,其中缓存数据的key定制为StringRedisSerializer(即String格式),而value定制为了Jackson2JsonRedisSerializer(即JSON格式),同时还使用entryTtl(Duration.ofDays(1))方法将缓存数据有效期设置为1天

完成基于注解的Redis缓存管理器RedisCacheManager定制后,可以对该缓存管理器的效果进行测试(使用自定义序列化机制的RedisCacheManager测试时,实体类可以不用实现序列化接口)

The above is the detailed content of How SpringBoot customizes Redis to implement cache serialization. For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:yisu.com. If there is any infringement, please contact admin@php.cn delete