场景
以懒汉式单例为例,通过添加在类中添加readResolve()方法可防止通过反序列化破坏单例
/**
* 懒汉式测试
* @author Administrator
*/
public class SingletonDemo02 implements Serializable {
/**
* 懒加载
*/
private static SingletonDemo02 instance;
private SingletonDemo02(){
//防止反射通过反射实例化对象而跳过getInstance方法
if(instance !=null){
throw new RuntimeException("Object has been instanced!!!");
}
}
/**
* 使用方法时才加载类,资源利用率高了,但需要线程同步
* @return SingletonDemo02
*/
public static synchronized SingletonDemo02 getInstance(){
if(instance==null){
instance=new SingletonDemo02();
}
return instance;
}
/**
* 提供readResolve()方法
* 当JVM反序列化地恢复一个新对象时,
* 系统会自动调用这个readResolve()方法返回指定好的对象,
* 从而保证系统通过反序列化机制不会产生多个java对象
*
* @return 单例对象
* @throws ObjectStreamException 异常
*/
private Object readResolve() throws ObjectStreamException {
return instance;
}
}
测试用例:
public class TestMain {
public static void main(String[] args) throws Exception {
SingletonDemo02 o3=SingletonDemo02.getInstance();
FileOutputStream fos=new FileOutputStream("D:\\Object.txt");
ObjectOutputStream oos=new ObjectOutputStream(fos);
oos.writeObject(o3);
oos.close();
fos.close();
ObjectInputStream ois=new ObjectInputStream(new FileInputStream("D:\\Object.txt"));
Object o4=ois.readObject();
System.out.println(o3==o4);
}
}
结果:
源码分析
在我们读取输入流创建Object对象时使用了readObject()方法。
Object o4=ois.readObject();
查看该方法的源码:
public final Object readObject()
throws IOException, ClassNotFoundException
{
if (enableOverride) {
//返回值为null
return readObjectOverride();
}
// if nested read, passHandle contains handle of enclosing object
int outerHandle = passHandle;
try {
Object obj = readObject0(false);
handles.markDependency(outerHandle, passHandle);
ClassNotFoundException ex = handles.lookupException(passHandle);
if (ex != null) {
throw ex;
}
if (depth == 0) {
vlist.doCallbacks();
}
return obj;
} finally {
passHandle = outerHandle;
if (closed && depth == 0) {
clear();
}
}
}
在创建Object对象时使用了 readObject0(false)
方法,进入该方法中,类初始化相关代码如下:
/**
* Underlying readObject implementation.
* 底层 readObject方法的实现
* 是类ObjectStreamClass的方法
*/
private Object readObject0(boolean unshared) throws IOException {
···
case TC_OBJECT:
return checkResolve(readOrdinaryObject(unshared));
···
}
可以看到这里调用了一个readOrdinaryObject(unshared)
方法,进入该方法中
/**
* 类ObjectInputStream的方法
* Reads and returns "ordinary" (i.e., not a String, Class,
* ObjectStreamClass, array, or enum constant) object, or null if object's
* class is unresolvable (in which case a ClassNotFoundException will be
* associated with object's handle). Sets passHandle to object's assigned
* handle.
*/
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 {
//这个desc可以理解为我们的单例类的class类,但是他和我们加载到内存中的单例class类有不同
//因为如果就是我们的单例class类是不允许再实例化的。
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;
}
可以看到在实例化Object对象obj时进行了一次判断,这里obj进行了第一次实例化
obj = desc.isInstantiable() ? desc.newInstance() : null;
isInstantiable()
方法用于判断该类是否能否实例化
/**
* Returns true if represented class is serializable/externalizable and can
* be instantiated by the serialization runtime--i.e., if it is
* externalizable and defines a public no-arg constructor, or if it is
* non-externalizable and its first non-serializable superclass defines an
* accessible no-arg constructor. Otherwise, returns false.
*/
boolean isInstantiable() {
//判断initializedc参数是否为空,为空抛出异常
requireInitialized();
//判断是否存在空的构造方法
return (cons != null);
}
直接看方法注释:当该类是一个可序列化类或外部类,可被实例化时返回true,要求外部类必须有一个公共的无参构造方法,可序列化类的第一个不可序列化父类定义了一个可访问的无参构造方法,否则返回false。
obj完成实例化后继续往下走
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;
其中hasReadResolveMethod()
用来判断readResolveMethod参数是否有值
/**
* Returns true if represented class is serializable or externalizable and
* defines a conformant readResolve method. Otherwise, returns false.
*/
boolean hasReadResolveMethod() {
requireInitialized();
return (readResolveMethod != null);
}
而readResolveMethod属性通过反射找到一个无参的readResolve方法进行赋值,而我们在单例类中自己重新定义了readResolve方法,也就是说这里会调用我们写的readResolve方法
readResolveMethod = getInheritableMethod(
cl, "readResolve", null, Object.class);
接下来我们又创建了一个Object对象rep,调用readResolve方法方法,调用的方式也是反射调用
/**
* Invokes the readResolve method of the represented serializable class and
* returns the result. Throws UnsupportedOperationException if this class
* descriptor is not associated with a class, or if the class is
* non-serializable or does not define readResolve.
*/
Object invokeReadResolve(Object obj)
throws IOException, UnsupportedOperationException
{
requireInitialized();
if (readResolveMethod != null) {
try {
return readResolveMethod.invoke(obj, (Object[]) null);
} catch (InvocationTargetException ex) {
Throwable th = ex.getTargetException();
if (th instanceof ObjectStreamException) {
throw (ObjectStreamException) th;
} else {
throwMiscException(th);
throw new InternalError(th); // never reached
}
} catch (IllegalAccessException ex) {
// should not occur, as access checks have been suppressed
throw new InternalError(ex);
}
} else {
throw new UnsupportedOperationException();
}
}
这次实例化根据我们在单例类中定义的那样,会返回一个已经实例化的instance单例对象,随后判断rep和obj是否相等,不等则将rep的值赋值给obj
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;
至此我们就完成了readObject方法,返回了我们需要的单例对象instance。在返回该对象的过程中,我们实例化了单例类obj,通过obj反射调用自身的readResolve方法,也就是我们自己定义的方法,获取instance对象。也就是说我们每获取一次单例对象instace之前都需要先实例化一次单例类,获取单例类对象obj,通过它才能获已经实例化的单例类对象instance。
流程总结
- 1.在我们的单例类中定义一个
readResolve()
方法,其中返回instance对象 - 2.反序列化获取单例类对象时调用
readObject()
方法 - 3.
readObject()
方法中调用其实现方法readObject0()
- 4.
readObject0()
方法中调用readOrdinaryObject(boolean unshared)
方法 - 5.
readOrdinaryObject(boolean unshared)
方法中获取单例类的ObjectStreamClass对象desc,判断该对象是否能实例化。可以则进行实例化,至此单例类进行了第一次实例化,对象名为obj - 6.第一次实例完成后,通过反射寻找该单例类中是否有
readResolve()
方法,如果没有则直接返回obj对象。这里就是我们对没有readResolve()
方法的类进行序列化操作后会生成不同对象的原因 - 7.当然这里我们有
readResolve()
方法,通过invokeReadResolve(Object obj)
方法调用readResolve()
方法获取到了单例对象instance,将他赋值给rep - 8.rep与obj进行比较,由于obj是通过反射获取到的对象,当然与rep不等,于是将rep的值instance赋值给obj,将obj返回,返回对象为instance也就保证了单例。
简而言之就是当我们通过反序列化readObject()
方法去获取对象时,会去寻找readResolve()
方法,如果该方法不存在则直接返回一个新的对象,如果该方法存在则按该方法的内容返回对象。