dubbo传递对象时,发送端和接受端对象serialVersionUID不一致会如何?

最近在做一个dubbo接口的时候,突然想到如果将发送对象的serialVersionUID改成和接受对象的serialVersionUID不一致时,会不会导致反序列化失败?

都知道在java的序列化和反序列化里面,如果传输对象的serialVersionUID前后不一致,用java序列化和反序列化时会报错。
java.io.InvalidClassException:stream classdesc serialVersionUID = 6457272772, local class serialVersionUID = -1923645274767028479 (可以查询java中serialVersionUID 的作用)

但是,在实际的dubbo接口测试过程中,特意更改了传输对象的前后的serialVersionUID,结果是依然可以成功的接受对象,即成功的序列化和反序列化

为什么?
开始困扰了好久,后来偶然看到一句话,“hessian2序列化:hessian是一种跨语言的高效二进制序列化方式。但这里实际不是原生的hessian2序列化,而是阿里修改过的hessian lite,它是dubbo RPC默认启用的序列化方式。”。后来就想,是不是因为序列化方式有关,会不会是Hessian序列化时并不会在意serialVersionUID的变化。

为证实心中的疑虑。分别采用了Hessian和java两种序列化方式进行验证。

这里有2个工程,一个发送端,一个接收端,采用SpringBoot启动,两个工程里面都分别载入了实体对象Person。用于测试对象serialVersionUID相同和不相同的情况。

1.第一个工程,是传输对象接受端,这里反序列化。serializabletest-server。3个主类
1.1.Person.java 传输对象。

@ToString
@Data
public class Person implements Serializable {

    private static final long serialVersionUID = -1923645274767028479L;

    private String[] address;

    private String name;

    private int phone;

}

1.2. HessianController.java hessian反序列化接受类。通过一个Controller接受http提交过来的对象信息


@Slf4j
@RestController
@RequestMapping("/hessian")
public class HessianController {

    @RequestMapping(value = "/hello")
    public String helloWorld(HttpServletRequest request, HttpServletResponse response) throws IOException {
        log.info("hessian反序列化开始------------------------");
        ServletInputStream sis = request.getInputStream();
        Hessian2Input h2i = new Hessian2Input(sis);
        h2i.startMessage();
        Person person = (Person) h2i.readObject();
        h2i.completeMessage();
        h2i.close();
        sis.close();
        log.info("hessian反序列化结果"+person.toString());
        return person.toString();
    }
}

1.3 JavaController.java Java反序列化接受类,通过一个Controller接受http提交过来的对象信息

@Slf4j
@RestController
@RequestMapping("/java")
public class JavaController {

    @RequestMapping(value = "/seri")
    public String helloWorld(HttpServletRequest request, HttpServletResponse response) throws Exception {

        log.info("java反序列化开始------------------------");
        ServletInputStream sis = request.getInputStream();
        ObjectInputStream is = new ObjectInputStream(sis);
        Person person = (Person) is.readObject();
        log.info("java"+person.toString());
        return person.toString();
    }
}

2、第二个工程,是传输对象发送端,这里进行对象序列化,并post发送请求。serializabletest-client。也是3个主类
2.1 Person.java


@ToString
@Data
public class Person implements Serializable {

    //通过变更serialVersionUID,分别测试与serializabletest-server中相同和不同的情况
    private static final long serialVersionUID = 6457272772L;

    private String[] address;

    private String name;

    private int phone;

}

2.2 HessianTest.java Hessian序列化对象 并发送

public class HessianTest {

    public static String urlName = "http://localhost:8080/hessian/hello";

    public static void main(String[] args) throws Throwable {

        // 序列化
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        Hessian2Output h2o = new Hessian2Output(os);
        h2o.startMessage();
        h2o.writeObject(getPerson());
        h2o.writeString("I am client.");
        h2o.completeMessage();
        h2o.close();

        byte[] buffer = os.toByteArray();
        os.close();
        ByteArrayEntity byteArrayEntity = new ByteArrayEntity(buffer,
                ContentType.create("x-application/hessian", "UTF-8"));

        CloseableHttpClient client = HttpClients.createDefault();
        HttpPost post = new HttpPost(urlName);
        post.setEntity(byteArrayEntity);
        CloseableHttpResponse response = client.execute(post);

        System.out.println("response status:\n"
                + response.getStatusLine().getStatusCode());
        HttpEntity body = response.getEntity();
        System.out.println("body:"+body);
    }

    public static Person getPerson() {
        Person person = new Person();
        person.setAddress(new String[] { "Beijing", "TaiWan", "GuangZhou" });
        person.setName("Jack");
        person.setPhone(188888888);
        return person;
    }

2.3 JavaTest.java java序列化并发送

public class JavaTest {

    public static String urlName = "http://localhost:8080/java/seri";

    public static void main(String[] args) throws Throwable {


        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutputStream os = new ObjectOutputStream(bos);
        os.writeObject(getPerson());
        byte[] buffer = bos.toByteArray();
        os.close();
        ByteArrayEntity byteArrayEntity = new ByteArrayEntity(buffer,
                ContentType.create("x-java-serialized-object", "UTF-8"));

        CloseableHttpClient client = HttpClients.createDefault();
        HttpPost post = new HttpPost(urlName);
        post.setEntity(byteArrayEntity);
        CloseableHttpResponse response = client.execute(post);

        System.out.println("response status:\n"
                + response.getStatusLine().getStatusCode());
        HttpEntity body = response.getEntity();
        System.out.println("body:"+body);
    }

    public static Person getPerson() {
        Person person = new Person();
        person.setAddress(new String[] { "Beijing", "TaiWan", "GuangZhou" });
        person.setName("Jack");
        person.setPhone(188888888);
        return person;
    }

}

3.测试:
这里分两种情况测试
3.1*测试第一种情况*
我们将发送端(serializabletest-client)中的person对象的serialVersionUID保持与serializabletest-server端一致,即将2.1中的serialVersionUID改为-1923645274767028479L 保持跟1.1一致。
分别运行HessianTest.java 和 JavaTest.java 得到serializabletest-server服务端中日志 如下
dubbo传递对象时,发送端和接受端对象serialVersionUID不一致会如何?_第1张图片

结论:当传输对象的serialVersionUID前后,这里两种方式Hessian和java都能成功序列化和反序列化操作

3.2*测试第二种情况*
将发送端和接受的端的serialVersionUID改为不一致。例,将2.1中的serialVersionUID改为6457272772L,1.1保持原来的值不变。 分别运行HessianTest.java 和 JavaTest.java 得到serializabletest-server服务端中日志 如下

dubbo传递对象时,发送端和接受端对象serialVersionUID不一致会如何?_第2张图片

结论:这里可以看到,在传输对象的serialVersionUID前后不一致时候,Hessian可以成功进行“反序列化”操作。但是java方式不能进行“反序列化”。

你可能感兴趣的:(java)