一.破坏单例模式
- 单例模式,是一种常见的软件设计模式。在它的核心结构中包含一个被称为单例的特殊类。通过单例模式可以保证系统中,应用该模式的一个类只有一个实例。
- 但是可以使用序列化对其进行破坏。
public class LazyDoubleCheckSingleton implements Serializable {
private volatile static LazyDoubleCheckSingleton lazyDoubleCheckSingleton = null;
private LazyDoubleCheckSingleton(){}
public static LazyDoubleCheckSingleton getInstance(){
if(lazyDoubleCheckSingleton == null){
synchronized (LazyDoubleCheckSingleton.class){
if(lazyDoubleCheckSingleton == null)
lazyDoubleCheckSingleton = new LazyDoubleCheckSingleton();
}
}
return lazyDoubleCheckSingleton;
}
}
LazyDoubleCheckSingleton instance1 = LazyDoubleCheckSingleton.getInstance();
LazyDoubleCheckSingleton instance2 = null;
try {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("singleton_file"));
oos.writeObject(instance1);
} catch (IOException e) {
e.printStackTrace();
}
try {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("singleton_file"));
try {
instance2 = (LazyDoubleCheckSingleton) ois.readObject();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
} catch (IOException e) {
e.printStackTrace();
}
System.out.println(instance1 == instance2);
- 如果对对象进行保存,必须首先对其进行序列化。其打印结果为
false
,这说明经过I/O操作后,对象的状态发生了变化。也就是说对象在序列化与反序列化时出现了问题。
二.跟踪源码
- 进入
ois.readObject()
方法。找到readObject0
方法
private Object readOrdinaryObject(boolean unshared)
throws IOException
{
if (bin.readByte() != TC_OBJECT) {
throw new InternalError();
}
ObjectStreamClass desc = readClassDesc(false);
desc.checkDeserialize();
Class<?> cl = desc.forClass();
if (cl == String.class || cl == Class.class
|| cl == ObjectStreamClass.class) {
throw new InvalidClassException("invalid class descriptor");
}
Object obj;
try {
//序列化会通过反射调用无参的构造方法创建一个新的对象
obj = desc.isInstantiable() ? desc.newInstance() : null;
} catch (Exception ex) {
throw (IOException) new InvalidClassException(
desc.forClass().getName(),
"unable to create instance").initCause(ex);
}
passHandle = handles.assign(unshared ? unsharedMarker : obj);
ClassNotFoundException resolveEx = desc.getResolveException();
if (resolveEx != null) {
handles.markException(passHandle, resolveEx);
}
if (desc.isExternalizable()) {
readExternalData((Externalizable) obj, desc);
} else {
readSerialData(obj, desc);
}
handles.finish(passHandle);
if (obj != null &&
handles.lookupException(passHandle) == null &&
desc.hasReadResolveMethod()) //注意这个方法
{
Object rep = desc.invokeReadResolve(obj);
if (unshared && rep.getClass().isArray()) {
rep = cloneArray(rep);
}
if (rep != obj) {
// Filter the replacement object
if (rep != null) {
if (rep.getClass().isArray()) {
filterCheck(rep.getClass(), Array.getLength(rep));
} else {
filterCheck(rep.getClass(), -1);
}
}
handles.setObject(passHandle, obj = rep);
}
}
return obj;
}
- 为了防止序列化对单例模式的破坏,可以在类中添加
readResolve
方法
public class LazyDoubleCheckSingleton implements Serializable {
private volatile static LazyDoubleCheckSingleton lazyDoubleCheckSingleton = null;
private LazyDoubleCheckSingleton(){}
public static LazyDoubleCheckSingleton getInstance(){
if(lazyDoubleCheckSingleton == null){
synchronized (LazyDoubleCheckSingleton.class){
if(lazyDoubleCheckSingleton == null)
lazyDoubleCheckSingleton = new LazyDoubleCheckSingleton();
}
}
return lazyDoubleCheckSingleton;
}
private Object readResolve(){
return lazyDoubleCheckSingleton;
}
}