`

序列化对象的singleton

 
阅读更多

  由于对象反序列化对象,总会生出一个新的实例,这使得原本的singleton对象,一旦实现了Serializable接口,就不能正常工作了,看代码:

 

public class Singleton implements Serializable {
	
	/**
	 * 
	 */
	private static final long serialVersionUID = -5902363018159528162L;

	private int count = 0;
	
	private static Singleton instance = new Singleton();
	static {
		System.out.println("static");
		instance = new Singleton();
	}
	private Singleton(){
	}
	
	public static Singleton getInstance(){
		return instance;
	}
	
	public int getCount() {
		return count;
	}

	public void setCount(int count) {
		this.count = count;
	}
}

 

 

测试代码:

 

@Test
	public void testSingletonWithSerializable() {
		storeSingleton();
		Singleton singleton = null;
	    singleton = restore();
	    singleton.setCount(10);
	    Singleton singleton1 = restore();
	    Assert.assertEquals(10, singleton1.getCount());
	}

	private Singleton restore() {
		Singleton singleton=null;
		try {
		    FileInputStream fis = new FileInputStream("d:\\singleton.txt");
		    ObjectInputStream ois = new ObjectInputStream(fis);
		    
		    singleton = (Singleton)ois.readObject();
		    
		} catch (Exception e) {
		    // TODO: handle exception
		    e.printStackTrace();
		}
		return singleton;
	}

	private void storeSingleton() {
		Singleton singleton = Singleton.getInstance();
	        try {
	            FileOutputStream fos = new FileOutputStream("d:\\singleton.txt");
	            ObjectOutputStream oos = new ObjectOutputStream(fos);
	            oos.writeObject(singleton);
	            oos.flush();
	            oos.close();
	        } catch (Exception e) {
	            // TODO: handle exception
	            e.printStackTrace();
	        }
	}

 

 运行后结果:

 

 写道

junit.framework.AssertionFailedError: expected:<10> but was:<0>
at junit.framework.Assert.fail(Assert.java:47)
at junit.framework.Assert.failNotEquals(Assert.java:283)
at junit.framework.Assert.assertEquals(Assert.java:64)
at junit.framework.Assert.assertEquals(Assert.java:195)
at junit.framework.Assert.assertEquals(Assert.java:201)
at ully.designpattern.singleton.SingletonTest.testSingletonWithSerializable(SingletonTest.java:32)

 

 显然,第二次读取的singleton对象是新的。

 

 

如此,如何解决此问题呢,答案是需要在Singleton类中添加一个回调方法:

 

 

private Object readResolve(){
		return instance;
	}

 这其实就相当于做了一个hack,代码在执行ObjectInputStream的readObject()方法时,会先去检查该序列化类是否有readResolve方法,如果有会将object替换成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
    {
	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();	// never reached
		}
	    } catch (IllegalAccessException ex) {
		// should not occur, as access checks have been suppressed
		throw new InternalError();
	    }
	} else {
	    throw new UnsupportedOperationException();
	}
    }

 

 

如此,添加了ReadResolve方法,即可保证每次反序列化的对象均是单例的。

分享到:
评论

相关推荐

    Singleton

    在实际开发中,我们还需要考虑Singleton的序列化问题,因为默认的序列化机制会破坏单例。可以通过实现Serializable接口并重写readResolve()方法来解决这个问题。 此外,Singleton模式虽然简单易用,但也有一些缺点...

    Singleton Pattern 源码

    这是Joshua Bloch在《Effective Java》中推荐的单例实现方式,既线程安全,又避免了序列化导致的多实例问题。 ```java public enum Singleton { INSTANCE; } ``` 单例模式虽然简单,但在某些情况下可能会带来...

    (创建型模式)Singleton模式

    这在某些情况下可能引发问题,比如测试和序列化。为了解决这些问题,可以考虑使用依赖注入或者使用Prototype模式作为替代。 总的来说,Singleton模式是一种常见的设计模式,它在适当的情况下可以简化系统设计,提高...

    设计模式之Singleton

    5. **枚举方式**:这是最安全且推荐的实现方式,天然线程安全,避免了序列化和反射攻击。 ```java public enum Singleton { INSTANCE; public void someMethod() { // ... } } ``` **单例模式的应用场景...

    设计模式之Singleton(单态)

    2. **序列化**:如果Singleton实现了Serializable接口,需处理反序列化时的实例化问题,否则可能会创建多个实例。 3. **测试**:测试Singleton类时,需考虑静态初始化可能导致的问题,可能需要特殊的测试策略。 4. *...

    Java单例模式设计

    默认情况下,单例对象是可序列化的。然而,序列化和反序列化可能会破坏单例模式,因为每次反序列化都会创建一个新的实例。为了防止这种情况,我们需要在Singleton类中实现`readResolve()`方法: ```java import ...

    singleton-demo.zip

    使用枚举来实现单例模式是一种既简单又安全的方式,同时防止反射和序列化攻击。 ```java public enum Singleton { INSTANCE; public void whateverMethod() { // ... } } ``` 以上六种单例模式各有优缺点...

    17-SingleTon.rar

    枚举类型是天然的单例,既保证了线程安全,又防止了反射和序列化攻击。 ```java public enum Singleton { INSTANCE; public void someMethod() { //... } } ``` 以上就是单例设计模式在Java中的多种实现方式...

    singleton demo

    另外,枚举类型的单例实现是Java中最安全且推荐的方式,因为它自动处理线程安全问题,同时也避免了反射和序列化攻击: ```java public enum Singleton { INSTANCE; } ``` 在这种实现中,`Singleton`是一个枚举...

    单例模式(singleton)

    此外,通过使用枚举方式实现单例,可以防止反射和序列化带来的多实例问题。 总结来说,单例模式是一种重要的设计模式,用于控制类实例的数量,以优化资源管理和提高效率。在实际开发中,我们需要根据具体需求选择...

    Singleton 单件(创建型模式)

    4. **枚举 Singleton**:这是 Bill Pugh 提出的一种创建 Singleton 实例的方法,既能防止反序列化重新创建新的实例,又避免了同步问题。代码如下: ```java public enum Singleton { INSTANCE; public void ...

    PHP面向对象程序设计之对象生成方法详解共4页.pdf.z

    这里,`$person`就是一个`Person`类的对象,`"张三"`和`25`作为参数传递给了构造函数,用于初始化对象的属性。 三、克隆对象:clone 关键字 有时候,我们可能需要复制一个已存在的对象而不希望改变原对象。这时...

    单例模式 Singleton Pattern

    5. **枚举**:JDK5之后引入的一种更简单的单例实现方式,天然支持序列化机制,能避免反射和反序列化的攻击。 ```java public enum Singleton { INSTANCE; public void showMessage() { System.out.println(...

    深入浅出单例Singleton模式

    2. **序列化**:如果单例类实现了`Serializable`接口,需要处理反序列化时可能创建新实例的问题,通常在`readResolve()`方法中返回现有实例。 3. **懒汉式与饿汉式**:懒汉式(延迟初始化)在类加载时不创建实例,...

    创建型模式之单例模式(Singleton Pattern)

    - 需要考虑反序列化时是否仍保持单例特性,否则可能创建多个实例。 总结来说,单例模式是一种常用的创建型设计模式,旨在保证类的实例只有一个,同时提供全局访问点。不同的实现方式有不同的性能和线程安全性考虑,...

    Head First 设计模式 (五) 单件模式(Singleton pattern) C++实现

    在实际使用中,除了考虑线程安全,还需要注意内存管理、序列化、测试等方面的问题。在C++中,单例模式常常与智能指针(如`std::unique_ptr`或`std::shared_ptr`)结合使用,以更好地管理对象的生命周期。

    Singleton.rar

    7. 枚举:最简单且推荐的实现方式,天然线程安全,避免反射和序列化攻击。 ```java public enum Singleton { INSTANCE; public void whateverMethod() { // ... } } ``` 以上就是Java中实现单例模式的常见方法...

    php7-singleton

    - `__wakeup`方法用于防止对象在反序列化时重新生成实例。 - 如果在多线程环境下,需要考虑线程安全问题,可能需要添加锁来保证同步。 通过Composer安装`darkfriend/php7-singleton`库,可以利用这个库提供的预封装...

    Java Singleton 实用教程(附源码)

    在实际开发中,我们还需要考虑反序列化和反射攻击破坏单例的情况,通常会在构造函数上添加`private`修饰符并使用`readResolve()`方法或`equals()`和`hashCode()`方法来防止这种情况发生。 总结起来,Java单例模式的...

Global site tag (gtag.js) - Google Analytics