美文网首页
序列化代理模式

序列化代理模式

作者: 元亨利贞o | 来源:发表于2016-07-01 23:40 被阅读409次

实现java.io.Serializable接口, 会增加出错和出现安全问题的可能性, 因为它开放了实例的另一种来源 ---- 反序列化. 有一种方法可以减少风险, 那就是序列化代理模式.

类图如下:

序列化代理模式.png

小二, 上代码 !

import java.io.InvalidObjectException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

/**
 * 1. 序列化Person时, 会调用调用writeReplace()生成一个PersonProxy对象, 然后对此对象进行序列化 (不是对Person类对象进行序列化,
 *      由序列化文件的内容可以得知, 可以查看序列化生成的文件, 文件中内容为如下图 (代码之后的图)
 * 2. 反序列化时, 会调用PersonProxy的readResolve()方法生成一个Person对象, 
 *      最后返回此对象的拷贝 (通过PersonProxy类的readResolve方法和main方法中的输出可以看出)
 * 3. 因此, Person类的序列化工作完全交给PersonProxy类, 正如此模式的名称所表达的一样
 */
public class Person implements Serializable {
    private final String name;
    private final String hobby;
    private final int age;

    public Person(String name, String hobby, int age) {
        System.out.println("Person(String name, String hobby, int age)");

        //约束条件
        if(age < 0 || age > 200) {
            throw new IllegalArgumentException("非法年龄");
        }

        this.name = name;
        this.hobby = hobby;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public String getHobby() {
        return hobby;
    }

    public int getAge() {
        return age;
    }


    private static class PersonProxy implements Serializable {
        private final String name;
        private final String hobby;
        private final int age;

        public PersonProxy(Person original) {
            System.out.println("PersonProxy(Person original)");
            this.name = original.getName();
            this.hobby = original.getHobby();
            this.age = original.getAge();
        }

        private Object readResolve() {
            System.out.println("PersonProxy.readResolve()");
            Person person = new Person(name, hobby, age);
            System.out.println("resolveObject: " + person);
            return person;
        }
    }

    private Object writeReplace() {
        System.out.println("Person.writeReplace()");
        return new PersonProxy(this); //readObject的时候是调用, PersonProxy的readResolve()
    }

    //此方法不会执行,
    private void writeObject(ObjectOutputStream out) {
        System.out.println("Person.writeObject()");
    }

    //防止攻击者伪造数据, 企图违反约束条件 (如: 违反年龄约束)
    private Object readObject(ObjectInputStream in) throws InvalidObjectException {
        System.out.println("Person.readObject()");
        throw new InvalidObjectException("Proxy required");
    }
}

序列化文件中的内容:

序列化文件内容

客户程序如下:

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

public class Main {
    public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
        Person person = new Person("张三", "足球" ,25);
        ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("serial.ser"));
        out.writeObject(person);
        out.flush();
        out.close();

        Thread.sleep(1000);

        ObjectInputStream in = new ObjectInputStream(new FileInputStream("serial.ser"));
        Person deserPerson = (Person) in.readObject();
        System.out.println("main: " + person);
        in.close();

        if(person == deserPerson) {
            System.out.println("序列化前后是同一个对象");
        } else {
            //程序会走这一段, 反序列化会创建对象, 但是不会执行类的构造方法, 而是使用输入流构造对象
            System.out.println("序列化前后不是同一个对象, 哈哈哈");
        }
    }
}

此模式工作原理如下:

  1. 序列化Person时, 会调用调用writeReplace()生成一个PersonProxy对象, 然后对此对象进行序列化 (不是对Person类对象进行序列化, 由序列化文件的内容可以得知, 可以查看序列化生成的文件, 文件中内容为如下图
序列化文件中的内容
  1. 反序列化时, 会调用PersonProxy的readResolve()方法生成一个Person对象, 最后返回此对象的拷贝 (通过PersonProxy类的readResolve方法和main方法中的输出可以看出)
  2. 因此, Person类的序列化工作完全交给PersonProxy类, 正如此模式的名称所表达的一样

本文参考: 《Effective Java 第2版》第78条 『考虑使用序列化代理代替序列化实例』

相关文章

  • java程序的性能优化(二)

    善用设计模式 单例模式:各类写法,反序列化破坏单例 代理模式:jdk接口代理,asm代理,cglib,javass...

  • 序列化代理模式

    实现java.io.Serializable接口, 会增加出错和出现安全问题的可能性, 因为它开放了实例的另一种来...

  • 设计模式

    单例模式 模板方法模式 工厂模式 代理模式 静态代理 JDK动态代理

  • 设计模式

    单例模式 代理模式 静态代理 jdk动态代理 cglib动态代理 工厂模式 适配器模式 建造者模式 观察者模式

  • kube-proxy的3种模式

    userspace代理模式 iptables代理模式 IPVS代理模式 https://kubernetes.io...

  • 第4章 结构型模式-代理模式

    一、代理模式简介 二、代理模式3个角色 三、代理模式的优点 四、代理模式的实例(游戏代练)

  • 理解代理模式

    原创博客地址 简介 代理模式,也叫做委托模式,分为:静态代理动态代理 代理模式也是平时比较常用的设计模式之一,代理...

  • 结构型 代理模式(文末有项目连接)

    1:什么是代理模式 2:没用代理模式时的实例 3:使用代理模式将其解耦(静态代理) 3:使用代理模式将其解耦(动态...

  • 设计模式-动态代理模式

    之前介绍了代理模式,大家也都了解了代理模式,不过之前介绍的代理模式是静态代理,静态代理什么意思?静态代理指的是代理...

  • 代理模式

    一、什么是代理模式 代理模式(Proxy pattern):代理模式又叫委托模式,是为某个对象提供一个代理对象,并...

网友评论

      本文标题:序列化代理模式

      本文链接:https://www.haomeiwen.com/subject/cqhqjttx.html