1 代码演练
1.1 克隆破坏单例
1.2 如何防范克隆破坏单例
1.3 小问
1 代码演练
1.1 克隆破坏单例
实体类:
package com.geely.design.pattern.creational.singleton; import java.io.Serializable; public class HangrySingleton implements Serializable,Cloneable { /** * 声明私有常量,当类初始化的时候就已经赋值了。饿汉式在类初始化的时候只加载一次。 * 所以也不会存在多线程的问题。 */ private final static HangrySingleton hangrySingleton; static { hangrySingleton= new HangrySingleton(); } /** * 声明私有构造方法 * 因为饿汉式和静态类在类初始化的时候,已经附上了对象,反射取值的时候该对象一定有值。 */ private HangrySingleton(){ if(hangrySingleton != null){ throw new RuntimeException("单例构造器禁止反射!"); } } @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } /** * 防止序列化和反序列化对单例模式进行破坏 */ private Object readResolve(){ return hangrySingleton; } /** * 提供对外接口,获得对象 * @return */ public static HangrySingleton getInstance(){ return hangrySingleton; } }
测试类:
package com.geely.design.pattern.creational.prototype; import com.geely.design.pattern.creational.singleton.HangrySingleton; import sun.reflect.Reflection; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Date; public class Test2 { public static void main(String [] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { /* Date date1 = new Date(); Pig pig1 = new Pig("peiqi",date1); Pig pig2 = (Pig) pig1.clone(); System.out.println(pig1); System.out.println(pig2); //预期修改pig1的生日,没想到pig2的生日也改了 pig1.getBirthday().setTime(0L); System.out.println(pig1); System.out.println(pig2);*/ //如何破坏单例模式?克隆方式破坏单例模式 HangrySingleton hangrySingleton = HangrySingleton.getInstance();//取得单例对象 //反射打开方法的权限 Method method = hangrySingleton.getClass().getDeclaredMethod("clone"); method.setAccessible(true); //克隆方法是protected权限,只有本类或者派生的类中使用,所以需要打开权限 HangrySingleton hangrySingleton2 = (HangrySingleton) method.invoke(hangrySingleton); System.out.println(hangrySingleton); System.out.println(hangrySingleton2); } }
打印日志:
"C:\Program Files\Java\jdk1.7.0_79\bin\java.exe" "-javaagent:D:\java\devolopKit\idea\anZh\IntelliJ IDEA Community Edition 2018.1.4\lib\idea_rt.jar=12734:D:\java\devolopKit\idea\anZh\IntelliJ IDEA Community Edition 2018.1.4\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.7.0_79\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.7.0_79\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.7.0_79\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.7.0_79\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.7.0_79\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.7.0_79\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.7.0_79\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.7.0_79\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.7.0_79\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.7.0_79\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.7.0_79\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.7.0_79\jre\lib\jce.jar;C:\Program Files\Java\jdk1.7.0_79\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.7.0_79\jre\lib\jfxrt.jar;C:\Program Files\Java\jdk1.7.0_79\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.7.0_79\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.7.0_79\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.7.0_79\jre\lib\resources.jar;C:\Program Files\Java\jdk1.7.0_79\jre\lib\rt.jar;F:\xiangmu3\Xin\Idea\design_pattern\target\classes" com.geely.design.pattern.creational.prototype.Test2
com.geely.design.pattern.creational.singleton.HangrySingleton@63ce0e18
com.geely.design.pattern.creational.singleton.HangrySingleton@6cff7cd8
Process finished with exit code 0
1.2 如何防范克隆破坏单例
a 单例类不实现克隆接口
b 这样修改
package com.geely.design.pattern.creational.singleton; import java.io.Serializable; public class HangrySingleton implements Serializable,Cloneable { /** * 声明私有常量,当类初始化的时候就已经赋值了。饿汉式在类初始化的时候只加载一次。 * 所以也不会存在多线程的问题。 */ private final static HangrySingleton hangrySingleton; static { hangrySingleton= new HangrySingleton(); } /** * 声明私有构造方法 * 因为饿汉式和静态类在类初始化的时候,已经附上了对象,反射取值的时候该对象一定有值。 */ private HangrySingleton(){ if(hangrySingleton != null){ throw new RuntimeException("单例构造器禁止反射!"); } } @Override protected Object clone() throws CloneNotSupportedException { return getInstance(); } /** * 防止序列化和反序列化对单例模式进行破坏 */ private Object readResolve(){ return hangrySingleton; } /** * 提供对外接口,获得对象 * @return */ public static HangrySingleton getInstance(){ return hangrySingleton; } }
1.3 小问
有哪些方式能够破坏单例模式呢?
克隆,
自己推测:序列化,反射攻击(可以翻看前边视频,后边有时间了再来巩固)