SpringBoot Redisシーケンス化の変更

14174 ワード

前言
Springbootのデフォルトでシーケンス化方式が提供されているのは理想的ではないため、要求が高い場合、シーケンス化の速度とシーケンス化後のサイズが要求されている場合は満足できないため、シーケンス化方式を交換する必要がある場合があります.ここでは、主に交換シーケンス化の方法と、いくつかの問題点を記録します.坑坑坑坑!今度踏んだ穴.
シーケンシャル方式の交換
最初のステップは、依存関係を追加する
//protostuffシーケンス化依存compile group:'io.protostuff', name: 'protostuff-runtime', version: '1.6.0' compile group: 'io.protostuff', name: 'protostuff-core', version: '1.6.0'
 
 
手順2では、シーケンス化ツールを追加します.
import io.protostuff.LinkedBuffer;
import io.protostuff.ProtostuffIOUtil;
import io.protostuff.Schema;
import io.protostuff.runtime.RuntimeSchema;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.SerializationException;

/**
* ProtoStuff     
* @author LinkinStar
*/
public class ProtostuffSerializer implements RedisSerializer {

private boolean isEmpty(byte[] data) {
    return (data == null || data.length == 0);
}

private final Schema schema;

private final ProtoWrapper wrapper;

private final LinkedBuffer buffer;

public ProtostuffSerializer() {
    this.wrapper = new ProtoWrapper();
    this.schema = RuntimeSchema.getSchema(ProtoWrapper.class);
    this.buffer = LinkedBuffer.allocate(LinkedBuffer.DEFAULT_BUFFER_SIZE);
}

@Override
public byte[] serialize(Object t) throws SerializationException {
    if (t == null) {
        return new byte[0];
    }
    wrapper.data = t;
    try {
        return ProtostuffIOUtil.toByteArray(wrapper, schema, buffer);
    } finally {
        buffer.clear();
    }
}

@Override
public T deserialize(byte[] bytes) throws SerializationException {
    if (isEmpty(bytes)) {
        return null;
    }
    ProtoWrapper newMessage = schema.newMessage();
    ProtostuffIOUtil.mergeFrom(bytes, newMessage, schema);
    return (T) newMessage.data;
}

private static class ProtoWrapper {
    private Object data;
}
}

 
 
 
ステップ3 RedisTemplateをカプセル化する
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;

/**
* Redis     
* @author LinkinStar
*/
@Component
public class RedisUtil {

@Autowired
@Qualifier("protoStuffTemplate")
private RedisTemplate protoStuffTemplate;

/**
 *       ,   
 * @param key     
 * @param timeout     
 * @return   :true,  :false
 */
public boolean setExpireTime(String key, long timeout) {
    return protoStuffTemplate.expire(key, timeout, TimeUnit.SECONDS);
}

/**
 *         
 * @param key     
 */
public void delete(String key) {
    protoStuffTemplate.delete(key);
}

/**
 *   key    
 * @param key     
 * @return   :true,   :false
 */
public boolean hasKey(String key) {
    return protoStuffTemplate.hasKey(key);
}

/**
 *     
 * @param key  
 * @param value  
 */
public void set(String key, Object value) {
    protoStuffTemplate.boundValueOps(key).set(value);
}

/**
 *              
 * @param key  
 * @param value  
 * @param expireTime     
 */
public void set(String key, Object value, Long expireTime) {
    protoStuffTemplate.boundValueOps(key).set(value, expireTime, TimeUnit.SECONDS);
}

/**
 *     
 * @param key  
 * @return     : ,    ,null
 */
public Object get(String key) {
    return protoStuffTemplate.boundValueOps(key).get();
}
}

 
 
 
ステップ4で、デフォルトのシーケンス化方法を変更します.
import com.linkinstars.springBootTemplate.util.ProtostuffSerializer;
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;
import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;

/**
* redisTemplate   ,  spring-session redis    
* @author LinkinStar
*/
@Configuration
@EnableRedisHttpSession
public class RedisConfig {

/**
 * redisTemplate       Serializeable,         ,          
 * @Rparam redisConnectionFactory
 * @return redisTemplate
 */
@Bean
public RedisTemplate protoStuffTemplate(RedisConnectionFactory redisConnectionFactory) {
    RedisTemplate template = new RedisTemplate<>();
    template.setConnectionFactory(redisConnectionFactory);

    // redis value       
    template.setValueSerializer(new ProtostuffSerializer());
    // redis key       
    template.setKeySerializer(new StringRedisSerializer());

    template.afterPropertiesSet();
    return template;
}
}

 
 
 
ステップ5、対応するテスト
//  redis
UserEntity user = new UserEntity();
user.setId(1);
user.setVal("xxx");

redisUtil.set("xxx", user);
Object object = redisUtil.get("xxx");
UserEntity userTemp = (UserEntity) object;

System.out.println("redis     : " + userTemp);
redisUtil.delete("xxx");
System.out.println("redis         : " + redisUtil.get("xxx"));

 
 
 
問題にぶつかる
問題の説明:シーケンス化後の逆シーケンス化は問題ありませんが、強制変換に対応するクラスに問題が発生し、強制変換できない例外が投げ出されます.問題分析:強制変換できません.説明は2つのクラスのクラスローダが異なる可能性があります.そのため、印刷の両方のクラスローダは確かに違います.クラスの1つのクラスのクラスローダにdevtoolという文字が表示されていることがわかり、ホットデプロイメントメカニズムがこのような問題を引き起こす可能性があることを連想しました.それからネットの資料を調べて、そして複数の機械の上でテストを行って、ある機械はこのような問題が現れないことを発見して、ある機械は現れます.Kryoを使用してシーケンス化すると、初めて上記の問題が発生し、protostuffホットデプロイメントを使用してからこの問題が発生します.問題解決:最後に、後で発生する可能性のある問題を回避するために、ホットデプロイされたdevtoolの対応する依存性と対応する構成が解決されることに注意します.
完全なコード
github:https://github.com/LinkinStars/springBootTemplate
参考ブログ:https://www.spldeolin.com/posts/redis-template-protostuff/https://blog.csdn.net/wsywb111/article/details/79612081https://github.com/protostuff/protostuff