Spring整合Redis序列化方式:StringRedisSerializer、FastJsonRedisSerializer和KryoRedisSerializer

在Spring框架中集成Redis時,選擇合適的序列化方式對於性能和數據的正確處理至關重要。本文將詳細介紹三種常用的Redis序列化方式:StringRedisSerializerFastJsonRedisSerializerKryoRedisSerializer,並探討它們的優缺點及適用場景。

1. StringRedisSerializer

1.1 簡介

StringRedisSerializer 是Spring Data Redis提供的一個默認的序列化器,主要用於字符串類型的序列化。它將對象轉換為字節數組,並且在反序列化時將字節數組轉換回字符串。

1.2 使用方法

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;

@Configuration
public class RedisConfig {

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(factory);
        template.setKeySerializer(new StringRedisSerializer());
        template.setValueSerializer(new StringRedisSerializer());
        return template;
    }
}

【詳解】Spring整合Redis序列化方式StringRedisSerializer、FastJsonRedisSerializer和KryoRedisSerializer_redis

1.3 優點

  • 簡單易用:適合簡單的字符串類型數據。
  • 性能高:由於不涉及複雜的對象轉換,性能較高。

1.4 缺點

  • 功能有限:僅支持字符串類型,無法直接處理複雜對象。

2. FastJsonRedisSerializer

2.1 簡介

FastJsonRedisSerializer 是基於阿里巴巴的FastJSON庫實現的序列化器,可以將Java對象轉換為JSON字符串,再將JSON字符串轉換為字節數組存儲到Redis中。

2.2 使用方法

首先,需要引入FastJSON的依賴:

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.78</version>
</dependency>

然後配置RedisTemplate

import com.alibaba.fastjson.support.spring.FastJsonRedisSerializer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;

@Configuration
public class RedisConfig {

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(factory);
        template.setKeySerializer(new StringRedisSerializer());
        template.setValueSerializer(new FastJsonRedisSerializer<>(Object.class));
        template.setHashKeySerializer(new StringRedisSerializer());
        template.setHashValueSerializer(new FastJsonRedisSerializer<>(Object.class));
        return template;
    }
}

2.3 優點

  • 支持複雜對象:可以處理複雜的Java對象。
  • 性能較好:FastJSON是一個高性能的JSON庫。

2.4 缺點

  • 佔用空間較大:JSON字符串通常比二進制數據佔用更多的空間。
  • 安全性問題:如果序列化的數據包含敏感信息,可能會存在安全風險。

3. KryoRedisSerializer

3.1 簡介

KryoRedisSerializer 是基於Kryo庫實現的序列化器,Kryo是一個高效的二進制序列化庫,特別適合於對象圖的序列化和反序列化。

3.2 使用方法

首先,需要引入Kryo的依賴:

<dependency>
    <groupId>com.esotericsoftware</groupId>
    <artifactId>kryo</artifactId>
    <version>5.3.0</version>
</dependency>

然後配置RedisTemplate

import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.io.ByteBufferOutput;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;
import com.esotericsoftware.kryo.pool.KryoFactory;
import com.esotericsoftware.kryo.pool.KryoPool;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.SerializationException;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import java.nio.ByteBuffer;

@Configuration
public class RedisConfig {

    private final KryoPool kryoPool = new KryoPool.Builder(new KryoFactory() {
        @Override
        public Kryo create() {
            Kryo kryo = new Kryo();
            kryo.setReferences(true);
            kryo.setRegistrationRequired(false);
            return kryo;
        }
    }).build();

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(factory);
        template.setKeySerializer(new StringRedisSerializer());
        template.setValueSerializer(new KryoRedisSerializer<>(kryoPool));
        template.setHashKeySerializer(new StringRedisSerializer());
        template.setHashValueSerializer(new KryoRedisSerializer<>(kryoPool));
        return template;
    }

    public static class KryoRedisSerializer<T> implements RedisSerializer<T> {

        private final KryoPool pool;

        public KryoRedisSerializer(KryoPool pool) {
            this.pool = pool;
        }

        @Override
        public byte[] serialize(T t) throws SerializationException {
            if (t == null) {
                return new byte[0];
            }
            try (Kryo kryo = pool.borrow()) {
                ByteBufferOutput output = new ByteBufferOutput(1024);
                Output out = new Output(output);
                kryo.writeClassAndObject(out, t);
                out.flush();
                return output.toBytes().array();
            } catch (Exception e) {
                throw new SerializationException("Serialization failed", e);
            }
        }

        @Override
        public T deserialize(byte[] bytes) throws SerializationException {
            if (bytes == null || bytes.length == 0) {
                return null;
            }
            try (Kryo kryo = pool.borrow()) {
                Input input = new Input(bytes);
                return (T) kryo.readClassAndObject(input);
            } catch (Exception e) {
                throw new SerializationException("Deserialization failed", e);
            }
        }
    }
}

3.3 優點

  • 高性能:Kryo的序列化和反序列化速度非常快。
  • 節省空間:二進制數據佔用的空間較小。

3.4 缺點

  • 兼容性問題:Kryo對類結構的變化比較敏感,如果類的字段發生變化,可能會導致反序列化失敗。
  • 配置複雜:需要配置Kryo池來管理Kryo實例,以提高性能。

【詳解】Spring整合Redis序列化方式StringRedisSerializer、FastJsonRedisSerializer和KryoRedisSerializer_spring_02

下面我將分別介紹如何在Spring Boot應用中使用StringRedisSerializerFastJsonRedisSerializerKryoRedisSerializer來配置Redis的序列化方式,並提供相應的示例代碼。

1. 使用 StringRedisSerializer

StringRedisSerializer 是最簡單的序列化方式,它將對象轉換為字符串存儲。適合存儲簡單的字符串數據。

示例代碼

首先,在你的Spring Boot項目中添加Redis依賴:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

然後,配置RedisTemplate使用 StringRedisSerializer

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;

@Configuration
public class RedisConfig {

    @Bean
    public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, String> template = new RedisTemplate<>();
        template.setConnectionFactory(factory);
        template.setKeySerializer(new StringRedisSerializer());
        template.setValueSerializer(new StringRedisSerializer());
        template.setHashKeySerializer(new StringRedisSerializer());
        template.setHashValueSerializer(new StringRedisSerializer());
        return template;
    }
}

2. 使用 FastJsonRedisSerializer

FastJsonRedisSerializer 使用阿里巴巴的FastJSON庫進行序列化,適合存儲複雜的Java對象。

示例代碼

首先,添加FastJSON依賴:

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.78</version>
</dependency>

然後,配置RedisTemplate使用 FastJsonRedisSerializer

import com.alibaba.fastjson.support.spring.FastJsonRedisSerializer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;

@Configuration
public class RedisConfig {

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(factory);

        FastJsonRedisSerializer<Object> fastJsonRedisSerializer = new FastJsonRedisSerializer<>(Object.class);

        // 設置鍵(key)的序列化採用StringRedisSerializer
        template.setKeySerializer(new StringRedisSerializer());
        template.setHashKeySerializer(new StringRedisSerializer());

        // 設置值(value)的序列化採用FastJsonRedisSerializer
        template.setValueSerializer(fastJsonRedisSerializer);
        template.setHashValueSerializer(fastJsonRedisSerializer);

        template.afterPropertiesSet();
        return template;
    }
}

3. 使用 KryoRedisSerializer

【詳解】Spring整合Redis序列化方式StringRedisSerializer、FastJsonRedisSerializer和KryoRedisSerializer_redis_03

KryoRedisSerializer 使用Kryo庫進行序列化,性能更高,但不支持所有類型的對象。

示例代碼

首先,添加Kryo和Kryo-serializer依賴:

<dependency>
    <groupId>com.esotericsoftware</groupId>
    <artifactId>kryo</artifactId>
    <version>5.2.0</version>
</dependency>
<dependency>
    <groupId>de.javakaffee</groupId>
    <artifactId>kryo-serializers</artifactId>
    <version>0.46</version>
</dependency>

然後,創建一個自定義的 KryoRedisSerializer 類:

import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.io.ByteBufferOutput;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;
import com.esotericsoftware.kryo.pool.KryoFactory;
import com.esotericsoftware.kryo.pool.KryoPool;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.SerializationException;

import java.nio.ByteBuffer;

public class KryoRedisSerializer<T> implements RedisSerializer<T> {

    private final ThreadLocal<Kryo> kryoThreadLocal = ThreadLocal.withInitial(() -> {
        Kryo kryo = new Kryo();
        kryo.setReferences(false);
        kryo.setRegistrationRequired(false);
        return kryo;
    });

    @Override
    public byte[] serialize(T t) throws SerializationException {
        if (t == null) {
            return new byte[0];
        }
        try (Output output = new ByteBufferOutput(1024)) {
            kryoThreadLocal.get().writeClassAndObject(output, t);
            return output.toBytes();
        } catch (Exception e) {
            throw new SerializationException("Serialization failed", e);
        }
    }

    @Override
    public T deserialize(byte[] bytes) throws SerializationException {
        if (bytes == null || bytes.length == 0) {
            return null;
        }
        try (Input input = new Input(bytes)) {
            return (T) kryoThreadLocal.get().readClassAndObject(input);
        } catch (Exception e) {
            throw new SerializationException("Deserialization failed", e);
        }
    }
}

最後,配置RedisTemplate使用 KryoRedisSerializer

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;

@Configuration
public class RedisConfig {

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(factory);

        KryoRedisSerializer<Object> kryoRedisSerializer = new KryoRedisSerializer<>(Object.class);

        // 設置鍵(key)的序列化採用StringRedisSerializer
        template.setKeySerializer(new StringRedisSerializer());
        template.setHashKeySerializer(new StringRedisSerializer());

        // 設置值(value)的序列化採用KryoRedisSerializer
        template.setValueSerializer(kryoRedisSerializer);
        template.setHashValueSerializer(kryoRedisSerializer);

        template.afterPropertiesSet();
        return template;
    }
}

以上就是三種不同的Redis序列化方式在Spring Boot中的配置示例。你可以根據實際需求選擇合適的序列化方式。在Spring框架中整合Redis時,選擇合適的序列化器對於性能和數據的正確處理至關重要。下面將詳細介紹三種常見的Redis序列化方式:StringRedisSerializerFastJsonRedisSerializerKryoRedisSerializer,並提供相應的代碼示例。

1. StringRedisSerializer

StringRedisSerializer 是最簡單的序列化方式,它將對象轉換為字符串。這種方式適用於簡單的字符串存儲需求。

配置示例
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;

@Configuration
public class RedisConfig {

    @Bean
    public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, String> template = new RedisTemplate<>();
        template.setConnectionFactory(factory);
        template.setKeySerializer(new StringRedisSerializer());
        template.setValueSerializer(new StringRedisSerializer());
        template.setHashKeySerializer(new StringRedisSerializer());
        template.setHashValueSerializer(new StringRedisSerializer());
        return template;
    }
}

2. FastJsonRedisSerializer

FastJsonRedisSerializer 使用阿里巴巴的FastJSON庫進行序列化和反序列化。FastJSON是一個非常高效的JSON處理庫,適合處理複雜的對象結構。

引入依賴

首先,需要在項目的pom.xml文件中添加FastJSON的依賴:

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.78</version>
</dependency>
自定義序列化器
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.support.config.FastJsonConfig;
import com.alibaba.fastjson.support.spring.FastJsonRedisSerializer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;

@Configuration
public class RedisConfig {

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(factory);

        // 設置key的序列化方式
        template.setKeySerializer(new StringRedisSerializer());

        // 設置value的序列化方式
        FastJsonRedisSerializer<Object> fastJsonRedisSerializer = new FastJsonRedisSerializer<>(Object.class);
        template.setValueSerializer(fastJsonRedisSerializer);

        // 設置hash key的序列化方式
        template.setHashKeySerializer(new StringRedisSerializer());

        // 設置hash value的序列化方式
        template.setHashValueSerializer(fastJsonRedisSerializer);

        return template;
    }

    @Bean
    public FastJsonRedisSerializer<Object> fastJsonRedisSerializer() {
        FastJsonConfig fastJsonConfig = new FastJsonConfig();
        fastJsonConfig.setSerializerFeatures(
                SerializerFeature.WriteMapNullValue, // 保留空的字段
                SerializerFeature.WriteNullStringAsEmpty, // 字符類型如果為null則輸出為""
                SerializerFeature.WriteNullNumberAsZero // 數字類型如果為null則輸出為0
        );
        return new FastJsonRedisSerializer<>(Object.class);
    }
}

3. KryoRedisSerializer

KryoRedisSerializer 使用Kryo庫進行序列化和反序列化。Kryo是一個高性能的序列化庫,特別適合於對象圖的高效序列化。

引入依賴

首先,需要在項目的pom.xml文件中添加Kryo的依賴:

<dependency>
    <groupId>com.esotericsoftware</groupId>
    <artifactId>kryo</artifactId>
    <version>5.3.0</version>
</dependency>
自定義序列化器
import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;
import com.esotericsoftware.kryo.pool.KryoFactory;
import com.esotericsoftware.kryo.pool.KryoPool;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.SerializationException;

import java.util.concurrent.Executors;

@Configuration
public class RedisConfig {

    private final KryoPool kryoPool = new KryoPool.Builder(new KryoFactory() {
        @Override
        public Kryo create() {
            Kryo kryo = new Kryo();
            kryo.setReferences(true);
            kryo.setRegistrationRequired(false);
            return kryo;
        }
    }).build();

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(factory);

        // 設置key的序列化方式
        template.setKeySerializer(new StringRedisSerializer());

        // 設置value的序列化方式
        template.setValueSerializer(kryoRedisSerializer());

        // 設置hash key的序列化方式
        template.setHashKeySerializer(new StringRedisSerializer());

        // 設置hash value的序列化方式
        template.setHashValueSerializer(kryoRedisSerializer());

        return template;
    }

    @Bean
    public RedisSerializer<Object> kryoRedisSerializer() {
        return new RedisSerializer<Object>() {
            @Override
            public byte[] serialize(Object t) throws SerializationException {
                if (t == null) {
                    return new byte[0];
                }
                try (Output output = new Output(Executors.newSingleThreadExecutor().submit(() -> {
                    byte[] buffer = new byte[1024];
                    return new Output(buffer, buffer.length);
                }).get())) {
                    kryoPool.run(kryo -> kryo.writeClassAndObject(output, t));
                    return output.toBytes();
                } catch (Exception e) {
                    throw new SerializationException("Serialization failed", e);
                }
            }

            @Override
            public Object deserialize(byte[] bytes) throws SerializationException {
                if (bytes == null || bytes.length == 0) {
                    return null;
                }
                try (Input input = new Input(bytes)) {
                    return kryoPool.run(kryo -> kryo.readClassAndObject(input));
                }
            }
        };
    }
}

總結

【詳解】Spring整合Redis序列化方式StringRedisSerializer、FastJsonRedisSerializer和KryoRedisSerializer_序列化_04

  • StringRedisSerializer:適用於簡單的字符串存儲。
  • FastJsonRedisSerializer:適用於複雜的對象結構,使用FastJSON進行高效的JSON序列化。
  • KryoRedisSerializer:適用於高性能的序列化需求,特別適合對象圖的高效序列化。

根據實際需求選擇合適的序列化器可以顯著提升應用的性能和穩定性。