栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

SpringWeb使用protostuff进行对象序列化

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

SpringWeb使用protostuff进行对象序列化

protobuf是Google推出的一种高效的序列化对象的方式,protostuff是基于protobuf的更容易使用的JAVA工具包。更加方便实现对象的序列化和反序列化。
代码如下:

		
		
            io.protostuff
            protostuff-runtime
            1.7.2
        
        
            io.protostuff
            protostuff-core
            1.7.2
        
进行序列化反序列化ProtoStuffUtil
public class ProtoStuffUtil {

    // proto stuff提供了简单的api,可以很方便的进行对象的序列化和反序列化,而不用像protoBuf还要去写.proto文件和生成对应的代码
    // 用来初始化buffer对象
    private static final ThreadLocal linkED_BUFFER = new ThreadLocal<>();

    @SuppressWarnings("unchecked")
    public static  byte[] serialize(T obj) {
        // 将对象序列化为byte数组
        Class clazz = (Class) obj.getClass();
        Schema schema = RuntimeSchema.getSchema(clazz);
        byte[] data;
        linkedBuffer buffer = getBuffer();
        try {
            data = ProtostuffIOUtil.toByteArray(obj, schema, buffer);
        } finally {
            // 清空buffer对象
            buffer.clear();
        }
        return data;
    }

    public static  void write(OutputStream stream, T value) throws IOException {
        // 将对象序列化到输出流
        Class clazz = (Class) value.getClass();
        Schema schema = RuntimeSchema.getSchema(clazz);
        linkedBuffer buffer = getBuffer();
        try {
            ProtobufIOUtil.writeTo(stream, value, schema, buffer);
        } finally {
            buffer.clear();
        }
    }

    public static  T deserialize(byte[] data, Class clazz) {
        // 将数组反序列化成对象
        Schema schema = RuntimeSchema.getSchema(clazz);
        T obj = schema.newMessage();
        ProtostuffIOUtil.mergeFrom(data, obj, schema);
        return obj;
    }

    public static  T deserialize(InputStream stream, Class clazz) throws IOException {
        // 将输入流序列化成对象
        Schema schema = RuntimeSchema.getSchema(clazz);
        T obj = schema.newMessage();
        ProtostuffIOUtil.mergeFrom(stream, obj, schema);
        return obj;
    }

    private static linkedBuffer getBuffer() {
        // 创建buffer,threadLocal没有的时候申请一个新的放进去,每个线程持有一个buffer对象,减少buffer对象的创建
        linkedBuffer linkedBuffer = linkED_BUFFER.get();
        if (linkedBuffer == null) {
            linkedBuffer = linkedBuffer.allocate(linkedBuffer.DEFAULT_BUFFER_SIZE);
            linkED_BUFFER.set(linkedBuffer);
        }
        return linkedBuffer;
    }

}
注册Spring的参数解析器和消息转换器
@Slf4j
public class ProtoStuffHttpMessageConverter extends AbstractHttpMessageConverter {
    // spring提供的消息转换器,对Content-type是x-protobuf进行序列化
    public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
    public static final MediaType MEDIA_TYPE = new MediaType("application", "x-protobuf", DEFAULT_CHARSET);
    public static final MediaType MEDIA_TYPE_GZIP = new MediaType("application", "x-protobuf-gzip", DEFAULT_CHARSET);

    
    public ProtoStuffHttpMessageConverter() {
        super(MEDIA_TYPE, MEDIA_TYPE_GZIP);
    }

    @Override
    public boolean canRead(final Class clazz, final MediaType mediaType) {
        return canRead(mediaType);
    }

    @Override
    public boolean canWrite(final Class clazz, final MediaType mediaType) {
        return canWrite(mediaType);
    }

    @Override
    protected Object readInternal(final Class clazz, final HttpInputMessage inputMessage)
            throws IOException, HttpMessageNotReadableException {
        if (MEDIA_TYPE.isCompatibleWith(inputMessage.getHeaders().getContentType())) {
            // 读取输入流序列化成对象
            try (InputStream stream = inputMessage.getBody()) {
                return ProtoStuffUtil.deserialize(stream, clazz);
            }
        }
        throw new HttpMessageNotReadableException("Unrecognized HTTP media type ", inputMessage);
    }

    @Override
    protected boolean supports(final Class clazz) {
        // Should not be called, since we override canRead/canWrite.
        throw new UnsupportedOperationException();
    }

    @Override
    protected void writeInternal(final Object o, final HttpOutputMessage outputMessage)
            throws IOException, HttpMessageNotWritableException {
        if (logger.isDebugEnabled()) {
            log.debug("Current type: {}", outputMessage.getHeaders().getContentType());
        }
        OutputStream stream = null;
        try {
            // 获取输出流
            stream = outputMessage.getBody();
            // 如果是gzip的包装成gzip流
            if (MEDIA_TYPE_GZIP.isCompatibleWith(outputMessage.getHeaders().getContentType())) {
                stream = new GZIPOutputStream(stream);
            }
            // 写到输出流
            ProtoStuffUtil.write(stream, o);
            // 刷新
            stream.flush();
        } finally {
            IOUtils.closeQuietly(stream);
        }
    }

}

// 参数解析


@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.PARAMETER})
public @interface ProtoStuffRequest {
}

@Component
public class ProtoStuffResolver implements HandlerMethodArgumentResolver {

    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        // ProtoStuffRequest注解的参数使用protostuff进行解析
        return parameter.hasParameterAnnotation(ProtoStuffRequest.class);
    }

    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
        ServletWebRequest request = (ServletWebRequest) webRequest;
        // 读取流解析对象
        try (ServletInputStream inputStream = request.getRequest().getInputStream()) {
            return ProtoStuffUtil.deserialize(inputStream, parameter.getParameterType());
        }
    }
}

// mvc配置
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

    // ProtoStuff的参数解析器
    @Autowired
    private ProtoStuffResolver protoStuffResolver;

    @Override
    public void addArgumentResolvers(List resolvers) {
    	// 添加参数解析器
        resolvers.add(protoStuffResolver);
    }

    @Override
    public void configureMessageConverters(List> converters) {
        // 配置消息转换器
        ProtoStuffHttpMessageConverter protoStuffHttpMessageConverter = new ProtoStuffHttpMessageConverter();
        converters.add(protoStuffHttpMessageConverter);
    }

}
 
测试接口 
// 实体对象
@Data
public class User {

    private Integer id;

    private String name;
}


@RestController
@RequestMapping("user")
public class UserController {

    @Autowired
    private UserMapper userMapper;

    
    @GetMapping("insert")
    public String insert(@ProtoStuffRequest User user) {
        userMapper.insertUser(user);
        return "success";
    }

	// 二是使用@RequestBody注解,但是要在请求的请求头中加上Content-Type application/x-protobuf
	@GetMapping("insert1")
    public String insert1(@RequestBody User user) {
        userMapper.insertUser(user);
        return "success";
    }

    
    @GetMapping("query")
    public User query(Integer id) {
        return userMapper.selectUser(id);
    }

 
}
测试结果

对象序列化:

对象反序列化:
insert:


insert1:

转载请注明:文章转载自 www.mshxw.com
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号