Dubbo——Dubbo协议整合Jackson序列化解决方案

本文档介绍了如何在Spring Boot 2.6.3、Spring Cloud 2021.0.1和Spring Cloud Alibaba 2021.0.1.0环境下,结合Nacos Server 2.0.4和Dubbo 2.7.15,实现自定义的Jackson序列化扩展。详细阐述了从编写JacksonSerialization、JacksonObjectInput和JacksonObjectOutput到注册SPI扩展的全过程,并提供了源代码示例。此外,还讨论了配置多协议的方法以及可能遇到的问题,如泛型对象序列化不支持。最后,给出了XML、Properties和YAML配置方式的示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

环境配置

spring boot 2.6.3
spring cloud 2021.0.1
spring cloud alibaba 2021.0.1.0
nacos server 2.0.4
dubbo 2.7.15

官方文档

序列化扩展:SPI扩展实现-序列化扩展
多协议配置:配置多协议

已知扩展

在这里插入图片描述

解决方案

源代码:https://gitee.com/myzstu/auth/tree/master/auth-core/src/main/java/club/zstuca/myzstu/dubbo/serialize/jackson

Maven 项目结构:

src
 |-main
    |-java
        |-com
            |-xxx
                |-XxxSerialization.java (实现Serialization接口)
                |-XxxObjectInput.java (实现ObjectInput接口)
                |-XxxObjectOutput.java (实现ObjectOutput接口)
    |-resources
        |-META-INF
            |-dubbo
                |-org.apache.dubbo.common.serialize.Serialization (纯文本文件,内容为:xxx=com.xxx.XxxSerialization)

JacksonSerialization.java:

package club.zstuca.myzstu.dubbo.serialize.jackson;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.serialize.ObjectInput;
import org.apache.dubbo.common.serialize.ObjectOutput;
import org.apache.dubbo.common.serialize.Serialization;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

/**
 * Jackson serialization implementation
 *
 * <pre>
 *     e.g. &lt;dubbo:protocol serialization="jackson" /&gt;
 * </pre>
 *
 * @author shentuzhigang
 * @date 2022/3/19 15:00
 */
public class JacksonSerialization implements Serialization {
    private final byte JACKSON_SERIALIZATION_ID = 31;

    private static ObjectMapper objectMapper = new ObjectMapper();

    public static synchronized void setObjectMapper(ObjectMapper objectMapper) {
        JacksonSerialization.objectMapper = objectMapper;
    }

    @Override
    public byte getContentTypeId() {
        return JACKSON_SERIALIZATION_ID;
    }

    @Override
    public String getContentType() {
        return "text/json";
    }

    @Override
    public ObjectOutput serialize(URL url, OutputStream output) throws IOException {
        return new JacksonObjectOutput(objectMapper, output);
    }

    @Override
    public ObjectInput deserialize(URL url, InputStream input) throws IOException {
        return new JacksonObjectInput(objectMapper, input);
    }
}

JacksonObjectInput.java:

package club.zstuca.myzstu.dubbo.serialize.jackson;

import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.type.TypeFactory;
import org.apache.dubbo.common.serialize.ObjectInput;

import java.io.*;
import java.lang.reflect.Type;

/**
 * Jackson object input implementation
 *
 * @author shentuzhigang
 * @date 2022/3/19 15:07
 */
public class JacksonObjectInput implements ObjectInput {

    private final ObjectMapper objectMapper;

    private final BufferedReader reader;

    public JacksonObjectInput(InputStream input) {
        this(new ObjectMapper(), input);
    }

    public JacksonObjectInput(ObjectMapper objectMapper, InputStream input) {
        this(objectMapper, new InputStreamReader(input));
    }

    public JacksonObjectInput(ObjectMapper objectMapper, Reader reader) {
        this.objectMapper = objectMapper;
        this.reader = new BufferedReader(reader);
    }

    @Override
    public boolean readBool() throws IOException {
        return read(boolean.class);
    }

    @Override
    public byte readByte() throws IOException {
        return read(byte.class);
    }

    @Override
    public short readShort() throws IOException {
        return read(short.class);
    }

    @Override
    public int readInt() throws IOException {
        return read(int.class);
    }

    @Override
    public long readLong() throws IOException {
        return read(long.class);
    }

    @Override
    public float readFloat() throws IOException {
        return read(float.class);
    }

    @Override
    public double readDouble() throws IOException {
        return read(double.class);
    }

    @Override
    public String readUTF() throws IOException {
        return read(String.class);
    }

    @Override
    public byte[] readBytes() throws IOException {
        return readLine().getBytes();
    }

    @Override
    public Object readObject() throws IOException, ClassNotFoundException {
        return objectMapper.readTree(readLine());
    }

    @Override
    public <T> T readObject(Class<T> cls) throws IOException, ClassNotFoundException {
        return read(cls);
    }

    @Override
    public <T> T readObject(Class<T> cls, Type type) throws IOException, ClassNotFoundException {
        JavaType javaType = TypeFactory.defaultInstance().constructType(type);
        return objectMapper.readValue(readLine(), javaType);
    }

    private String readLine() throws IOException, EOFException {
        String line = reader.readLine();
        if (line == null || line.trim().length() == 0) {
            throw new EOFException();
        }
        return line;
    }

    private <T> T read(Class<T> cls) throws IOException {
        String json = readLine();
        return objectMapper.readValue(json, cls);
    }
}

JacksonObjectOutput.java:

package club.zstuca.myzstu.dubbo.serialize.jackson;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.dubbo.common.serialize.ObjectOutput;

import java.io.*;

/**
 * Jackson object output implementation
 *
 * @author shentuzhigang
 * @date 2022/3/19 15:06
 */
public class JacksonObjectOutput implements ObjectOutput {

    private final ObjectMapper objectMapper;

    private final PrintWriter writer;

    public JacksonObjectOutput(OutputStream output) {
        this(new ObjectMapper(), output);
    }

    public JacksonObjectOutput(ObjectMapper objectMapper, OutputStream out) {
        this(objectMapper, new OutputStreamWriter(out));
    }

    public JacksonObjectOutput(ObjectMapper objectMapper, Writer writer) {
        this.objectMapper = objectMapper;
        this.writer = new PrintWriter(writer);
    }

    @Override
    public void writeBool(boolean v) throws IOException {
        writeObject(v);
    }

    @Override
    public void writeByte(byte v) throws IOException {
        writeObject(v);
    }

    @Override
    public void writeShort(short v) throws IOException {
        writeObject(v);
    }

    @Override
    public void writeInt(int v) throws IOException {
        writeObject(v);
    }

    @Override
    public void writeLong(long v) throws IOException {
        writeObject(v);
    }

    @Override
    public void writeFloat(float v) throws IOException {
        writeObject(v);
    }

    @Override
    public void writeDouble(double v) throws IOException {
        writeObject(v);
    }

    @Override
    public void writeUTF(String v) throws IOException {
        writeObject(v);
    }

    @Override
    public void writeBytes(byte[] v) throws IOException {
        writer.println(new String(v));
    }

    @Override
    public void writeBytes(byte[] v, int off, int len) throws IOException {
        writer.println(new String(v));
    }

    @Override
    public void writeObject(Object obj) throws IOException {
        writer.write(objectMapper.writeValueAsString(obj));
        writer.println();
        writer.flush();
    }

    @Override
    public void flushBuffer() throws IOException {
        writer.flush();
    }
}

META-INF/dubbo/org.apache.dubbo.common.serialize.Serialization:

jackson=club.zstuca.myzstu.dubbo.serialize.jackson.JacksonSerialization

ObjectMapper:
默认情况下,Jackson序列化和反序列化时所使用的ObjectMapper定义如下:

  @Override
    public ObjectMapper getObjectMapper() {
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
//            objectMapper.disable(SerializationFeature.FLUSH_AFTER_WRITE_VALUE);
        objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
        objectMapper.setTimeZone(TimeZone.getDefault());
        return objectMapper;
}

使用

provider

XML
<dubbo:protocol name="dubbo" port="20880" serialization="jackson" />
配置文件
Properties
dubbo.protocols.id=jackson
dubbo.protocols.name=dubbo
dubbo.protocols.port=20880
dubbo.protocols.serialization=jackson
YAML
dubbo:
  config:
    multiple: true
  protocols:
    dubbo:
      id: dubbo
      name: dubbo
      port: -1
    jackson:
      id: jackson
      name: dubbo
      port: 20880
      serialization: jackson

consumer

无需其他配置

常见问题

  1. 不支持泛型对象的序列化, 如 List,Map类型的序列化和反序列化

参考文章

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Starzkg

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值