序列化代理模式-readResolve()和writeReplace()
时间:2020-01-09 10:35:19 来源:igfitidea点击:
在本文中,我们将讨论序列化代理模式,这是通过序列化代理对象来序列化对象的一种更安全的方法。
需要序列化代理模式
Java中的序列化确实存在一些问题,例如
1.我们对整个序列化过程没有太多控制权。随着时间的推移更改类还会导致与序列化对象的兼容性问题。
2.在序列化中,实际对象被序列化,这增加了安全风险。任何攻击者都可以从序列化状态重建实际对象,或者更改流以操纵对象数据。
使用序列化代理模式,我们可以保护序列化过程。代理对象而不是实际对象被序列化。为了获得代理对象,我们需要在一个真实的类中创建一个静态内部类,该类也实现了Serializable接口,并且具有与实际类相同的字段。
Java中的readResolve()和writeReplace()方法
我们需要实现两个方法readResolve()和writeReplace()才能正确实现序列化代理模式。
writeReplace()–此方法由想要将代理对象写入流的Serializable类实现。
ANY-ACCESS-MODIFIER Object writeReplace() throws ObjectStreamException;
readResolve()–从流中读取实例的实例时需要返回替换的类应实现此方法。从流中读取代理对象时,必须以序列化代理模式返回实际对象,因此必须在代理类中实现此方法。
ANY-ACCESS-MODIFIER Object readResolve() throws ObjectStreamException;
序列化代理模式Java示例
这是一个其对象必须使用序列化代理模式进行序列化的类,因此它将具有静态内部类,并且也实现了readResolve()和writeReplace()方法。
import java.io.Serializable; public class Employee implements Serializable{ private static final long serialVersionUID = -8690951276691191306L; private String name; private String dept; private int salary; private int age; Employee(String name, String dept, int salary, int age){ this.name = name; this.dept = dept; this.salary = salary; this.age = age; } //writeReplace method for the proxy pattern private Object writeReplace() { System.out.println("In writeReplace() method"); return new EmployeeProxy(this); } private void readObject(ObjectInputStream ois) throws InvalidObjectException{ throw new InvalidObjectException("Use proxy class"); } private static class EmployeeProxy implements Serializable{ private String name; private String dept; private int salary; private int age; EmployeeProxy(Employee emp){ this.name = emp.name; this.dept = emp.dept; this.salary = emp.salary; this.age = emp.age; } // readResolve method in Proxy class private Object readResolve() { System.out.println("In readResolve() method"); return new Employee(name, dept, salary, age); } } // setters and getters }
我们应注意的一些重要事项是:
- EmployeeProxy类定义为静态内部类。代理类还实现了Serializable接口。
- EmployeeProxy类的构造函数将Employee对象作为参数,并使用它创建一个代理对象。在需要时创建代理对象时,我们也可以加密数据以使其更安全。
- Employee类实现了writeReplace()方法,该方法返回代理类的实例。
- EmployeeProxy类实现readResolve()方法并返回Employee对象。
5.作为添加的预防措施,还应实现readObject()方法以引发异常。这样就没有机会从流中构造Employee对象。
这是带有用于序列化和反序列化对象的方法的类。
public class SerializationDemo { public static void main(String[] args) { Employee emp = new Employee("Ryan", "IT", 7500, 35); final String fileName = "F:\theitroad\emp.ser"; serialzeObject(emp, fileName); /// Do null check here Employee e = (Employee)deSerializeObject(fileName); System.out.println("Name- " + e.getName()); System.out.println("Dept- " + e.getDept()); System.out.println("Salary- " + e.getSalary()); System.out.println("Age- " + e.getAge()); } // Method to serialize object public static void serialzeObject(Object obj, String fileName) { try(ObjectOutputStream outStream = new ObjectOutputStream(new FileOutputStream(fileName))){ outStream.writeObject(obj); } catch (IOException e) { // TODO Auto-generated e.printStackTrace(); } } // Method to deserialize object public static Object deSerializeObject(String fileName){ Object obj = null; try(ObjectInputStream inStream = new ObjectInputStream(new FileInputStream(fileName))){ obj = inStream.readObject(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (ClassNotFoundException e) { System.out.println("No class found for serialization"); e.printStackTrace(); } return obj; } }
输出:
In writeReplace() method to serialize proxy In readResolve() method to get actual object Name- Ryan Dept- IT Salary- 7500 Age- 35