(单例设计模式之一)饿汉式的反射与反序列化漏洞

1.闲话少说,直接上代码。

import java.io.Serializable;
//饿汉式
public class Singleton01 implements Serializable{
    //1.私有的属性
    private static Singleton01 instance=new Singleton01();
    //2.私有的构造器
    private Singleton01(){}
    //3.共有的get()方法
    public static  Singleton01 getInstance(){//这里不需要加同步块synchronized
        return instance;
    }
}

为什么不需要加同步块?这里插播一条短消息

1.  饿汉式是天然的线程安全的,因此不需要加线程锁。饿汉式之所以是天然的线程安全,是因为:

一个字节码文件被加载到内存会经历以下过程:

1、链接(1、验证2、准备3、解析)

2、初始化

3、使用

4、卸载

初始化是执行类构造器<clinit>()方法的过程。类构造器<clinit>()方法是由编译器自动收集类中的所有类变量的赋 值动作和静态语句块(static)中的语句合并产生的。在这个过程中instance已经被实例化了。并且虚拟机JVM会保证一个类 的<clinit>()方法在多线程的环境中被正确加锁和同步。因此他是天然线程安全的。

2.下面代码分析如何使用反射破解懒汉式:

public class Singletons_Test_02 {

public static void main(String[] args) throws Exception {

   Class<Singleton01> clazz = (Class<Singleton01>) Class.forName("com.shc.singleton.Singleton01");
        Constructor<Singleton01> c = clazz.getDeclaredConstructor(null);//获得无参构造器
        c.setAccessible(true);//跳过权限检查,访问私有的构造器
        Singleton01 s3 = c.newInstance();
        Singleton01 s4 = c.newInstance();
        System.out.println(s3);
        System.out.println(s4);

  }

}

此时输出s3与s4的哈希值是相等的。代表不是同一个对象,饿汉式单例通过反射破解完成。

3.下面分析饿汉式如何避免反射漏洞?

public class Singleton1 {

//1.私有的属性
    private static Singleton1 instance=new Singleton1();
    //2.私有的构造器
    private Singleton1(){
        if (null != instance) {
            throw new RuntimeException();
        }
    }
    //3.共有的get()方法
    public static  Singleton1 getInstance(){//天然的线程安全,不需要加同步块,因此调用效率高
        return instance;
    }
}

在私有的构造器中加一个判断,判断要创建的对象是否存在,如果不存在再创建,已存在就抛出运行时异常。

4.下面利用序列化与反序列化漏洞破解饿汉式单例

public class Singletons_Test_03 {

public static void main(String[] args) throws Exception {

    Singleton01 s1 = Singleton01.getInstance();
        Singleton01 s2 = Singleton01.getInstance();
        System.out.println(s1);
        System.out.println(s2);
        
        //序列化
        FileOutputStream fos = new FileOutputStream("../a.txt");
        ObjectOutputStream oos = new ObjectOutputStream(fos);
        oos.writeObject(s1);
        oos.close();
        fos.close();
        
        //反序列化
         ObjectInputStream ois =new ObjectInputStream(new FileInputStream("../a.txt"));
         Singleton01 s3 = (Singleton01) ois.readObject();
         System.out.println(s3);

  }

}

5.破解饿汉式反序列化漏洞

public class Singleton11 implements Serializable{
    //1.私有的属性
    private static Singleton11 instance=new Singleton11();
    //2.私有的构造器
    private Singleton11(){}
    //3.共有的get()方法
    public static Singleton11 getInstance(){
        return instance;
    }
    //反序列化时(加这个方法可以防止反序列化漏洞)
    private Object readResolve() throws ObjectStreamException{
        return instance;
    }
}

以上demo较为简单,不做深入研究,设计模式体验重在应用。

时间: 2025-01-31 06:26:40

(单例设计模式之一)饿汉式的反射与反序列化漏洞的相关文章

单例设计模式之饿汉式(静态常量)

package com.waibizi; /** * 单例设计模式之饿汉式(静态常量) * 步骤 * 1.构造器私有化(防止new) * 2.类的内部创建对象 * 3.向外暴露一个静态的公共方法 getInstance * 4.代码实现 * @author 歪鼻子 * * *优点:这种写法比较简单,类加载的时候就完成了实例化.避免了线程同步问题 *缺点:类装载的时候就完成了实例化,如果从开始到至终都没使用过这个类,势必会造成资源的浪费 *结论:这种单例模式是可用的,可能会导致浪费(调用getIn

单例设计模式之饿汉式(静态代码块)

package com.waibizi.demo02; /** * 单例设计模式之饿汉式(静态代码块) * 这种方式与饿汉式静态常量的方式是类似的,类装载的时候也有直接创建对象 * @author 歪鼻子 * */ @SuppressWarnings("all") public class Singleton_Pattern { public static void main(String[] args) { // TODO Auto-generated method stub } }

单例设计模式之饿汉式与懒汉式

/* 设计模式:对问题行之有效的解决方式.其实它是一种思想. 1,单例设计模式. 解决的问题:就是可以保证一个类在内存中的对象唯一性. 必须对于多个程序使用同一个配置信息对象时,就需要保证该对象的唯一性. 如何保证对象唯一性呢? 1,不允许其他程序用new创建该类对象. 2,在该类创建一个本类实例. 3,对外提供一个方法让其他程序可以获取该对象. 步骤: 1,私有化该类构造函数. 2,通过new在本类中创建一个本类对象. 3,定义一个公有的方法,将创建的对象返回. */ //饿汉式 class

单例设计模式---懒汉式+饿汉式

package com.Thread; /** * 单例设计模式:确保一个类只有一个对象 */ public class Synchronized_Singleton { public static void main(String[] args) { JvmThread jvm1= new JvmThread(100); JvmThread jvm2= new JvmThread(100); jvm1.start(); jvm2.start(); } } /** * 懒汉式(饿汉式:在声明静态

Spring -11 -单例设计模式 -懒汉式/饿汉式(idea默认的)

单例设计模式 作用: 在应用程序有保证最多只能有一个实例. 好处: 2.1 提升运行效率. 2.2 实现数据共享. 案例:application 对象 懒汉式 3.1 对象只有被调用时才去创建. 3.2  示例代码 3.3由于添加了锁,所以导致效率低. public class lazySingleton { //懒汉式,单例模式! //由于对象需要被静态方法调用,把方法设置为static //由于对象是static,必须要设置访问权限修饰符为private , //如果是public 可以直接

java===单类设计模式之饿汉式与懒汉式

package cn.china; public class Single { public static void main(String[]args){ // S singles=S.getInstance(); // S singless=S.getInstance(); // System.out.println(singles==singless); Test tt=Test.getInstance(); Test ttt=Test.getInstance(); tt.setNum(1

Java---15---单例设计模式:---饿汉式和懒汉式

概念: 单例模式确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实例.   单例模式有以下特点: 1.单例类只能有一个实例 2.单例类必须自己给自己创建自己的唯一实例 3.单例类必须给所有其他对象提供这一实例 饿汉式: /*饿汉式*/ class Single { private static final Single s = new Single(); private Single () {} public static Single getInstance() { return s

设计模式中饿汉式单例类和懒汉式单例类

单例模式的特点为: *单例类只有一个实例. *单例类必须自己创建自己的唯一实例. *单例类必须给所有其他对象提供这一实例. 饿汉式单例类: 而饿汉式单例类则在java语言中是最为简单的单例类,这是一个描述饿汉式单例类的类图的实现. 此类图中,此类已经将自己实例化. 源码为: package singleton; public class EagerSingleton { private static EagerSingleton instance=new EagerSingleton(); /*

单例设计模式懒汉式和恶汉式

一,单例设计模式懒汉式和恶汉式 懒汉式在类加载时不初始化,延迟加载.(配置文件) 饿汉式在类加载时初始化,加载慢,获取对象快. 饿汉式是线程安全的, 懒汉式需要加synchronized,否则不安全. 二,饿汉式 1 public class Singletonehan { 2 private static Singletonehan singleton=new Singletonehan(); 3 private Singletonehan() { 4 } 5 public static Si