当前位置: 首页 > news >正文

htm网站在网站建设中 为了防止工期拖延

htm网站,在网站建设中 为了防止工期拖延,深圳深网站建设服务,建立网站要多少钱一年✅如何破坏单例模式 #x1f4a1;典型解析✅拓展知识仓✅反射破坏单例✅反序列化破坏单例✅ObjectlnputStream ✅总结✅如何避免单例被破坏✅ 避免反射破坏单例✅ 避免反序列化破坏单例 #x1f4a1;典型解析 单例模式主要是通过把一个类的构造方法私有化#xff0c;来避免重… ✅如何破坏单例模式 典型解析✅拓展知识仓✅反射破坏单例✅反序列化破坏单例✅ObjectlnputStream ✅总结✅如何避免单例被破坏✅ 避免反射破坏单例✅ 避免反序列化破坏单例 典型解析 单例模式主要是通过把一个类的构造方法私有化来避免重复创建多个对象的。那么想要破坏单例只要想办注能够执行到这个私有的构造方法就行了。 ✅拓展知识仓 一般来说做法有使用反射及使用反序列化都可以破坏单例。 我们先通过双重校验锁的方式创建一个单例后文会通过反射及反序列化的方式尝试破坏这个单例。 package com.yangxiaoyuan;import java.io.Serializable;/*** Created by yangxiaoyuan on 23/12/24* 使用双重校验锁方式实现单例 */public class Singleton implements Serializable {private volatile static Singleton singleton;private Singleton () {}public static Singleton getsingleton() {if (singleton null) {synchronized (Singleton.class) {if (singleton null) {singleton new Singleton();}}}return singleton;} }✅反射破坏单例 我们尝试通过反射技术来破坏单例: Singleton singleton1 Singleton.getSingleton();//通过反射获取到构造函数 ConstructorSingleton constructor Singleton.class.getDeclaredConstructor(); //将构造函数设置为可访问类型 constructor.setAccessible(true); //调用构造函数的newInstance创建一个对象 Singleton singleton2 constructor.newInstance(); //判断反射创建的对象和之前的对象是不是同一个对象 System.out.println(s1 s2);以上代码输出结果为false也就是说通过反射技术我们给单例对象创建出来了一个 兄弟” 。 setAccessible(true)使得反射对象在使用时应该取消Java 语言访检查使得私有的构造函数能够被访问。 ✅反序列化破坏单例 我们尝试通过序列化反序列化来破坏一下单例: package com.yangxiaoyuan;import java.io.*;public class SerializableDemo1 {//为了便于理解忽略关闭流操作及删除文件操作。真正编码时千万不要忘记//Exception直接抛出public static void main(String args) throws IOException, ClassNotFoundException {//Write Obj to fileObjectOutputStream oos new ObjectOutputStream(new File0utputStream(tempFile));oos.writeObject(Singleton.getsingleton());//Read Obi from fileFile file new File(tempFile);ObjectInputStream ois new ObjectInputStream(new FileInputStream(file));Singleton newInstance (Singleton) ois.readObject();//判断是否是同一个对象System.out.println(newInstance Singleton.getSingleton());} }//false 输出结构为false说明: 通过对Singleton的序列化与反序列化得到的对象是一个新的对象这就破坏了Singleton的单例性。 这里在介绍如何解决这个问题之前我们先来深入分析一下为什么会这样?在反序列化的过程中到底发生了什么。 ✅ObjectlnputStream 对象的序列化过程通过ObjectOutputStream和ObiectlnputStream来实现的那么带着刚刚的问题分析一下ObjectlnputStream 的 readobject 方法执行情况到底是怎样的。 为了节省篇幅这里给出ObiectlnputStream的 readobject 的调用栈 这里看一下重点代码readOrdinaryObject 万法的代码片段: code 3 private Object readOrdinaryObject(boolean unshared) throws IOException {//此处省略部分代码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);}//此处省略部分代码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) {handles.setObject(passHandle, obj rep);}}return obj; }code 3 中主要贴出两部分代码。先分析第一部分 code3.1 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);}这里创建的这个obj对象就是本方法要返回的对象也可以暂时理解为是ObjectlnputStream的 readobject 返回的对象。 ![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/d9179a634e2a462dafeaf5c696d1a6f7.png#pic_center isInstantiable: 如果一个serializable/externalizable的类可以在运行时被实例化那么该方法就返回true。针对serializable和externalizable我会在其他文章中介绍。 desc.newInstance:该方法通过反射的方式新建一个对象。 然后看一下 newInstance 的源码: public T newInstance(Object ... initargs) throws InstantiationException IllegalAccessException, IllegalArgumentExceptionInvocationTargetException {if (!override) {if (!Reflection.quickCheckMemberAccess(clazzmodifiers)) {Class? caller Reflection.getCallerClass();checkAccess(caller, clazz, nul1, modifiers);}}if ((clazz.getModifiers() Modifier.ENUM) ! 0) {throw new IllegalArgumentException(Cannot reflectively create enum objects);}ConstructorAccessor ca constructorAccessor; // read volatileif (ca null) {ca acquireConstructorAccessor();}Suppresslarnings(unchecked)T inst (T) ca.newInstance(initargs];return inst; }其中关键的就是 T inst (T) ca.newInstance(initargs);这一步这里实现的话在BootstrapConstructorAccessorlmpl中实现如下 public Object newInstance(Object[] args) throws IllegalArgumentExceptionInvocationTargetException {try {return UnsafeFieldAccessorImpl.unsafe.allocateInstance(constructor.getDeclaringClass());} catch (InstantiationException e) {throw new InvocationTargetException(e);} }可以看到这里通过Java 的 Unsafe 机制来创建对象的而不是通过调用构造函数。这意味着即使类的构造函数是私有的反序列化仍然可以创建该类的实例因为它不依赖于常规的构造过程。 So到目前为止也就可以解释为什么序列化可以破坏单例 答序列化会通过Unsafe直接分配的方式来创建一个新的对象。 ✅总结 在涉及到序列化的场景时要格外注意他对单例的破坏。 ✅如何避免单例被破坏 ✅ 避免反射破坏单例 反射是调用默认的构造函数创建出来的只需要我们改造下构造函数使其在反射调用的时候识别出来对象是不是被创建过就行了 private Singleton() {if (singleton ! null) {throw new RuntimeException(单例对象只能创建一次...);} }✅ 避免反序列化破坏单例 解决反序列化的破坏单例只需要我们自定义反序列化的策略就行了就是说我们不要让他走默认逻辑一直调用至Unsafe创建对象而是我们干预他的这个过程干预方式就是在Singleton类中定义 readResolve 这样就可以解决该问题: package com.yangxiaoyuan;import java.io.Serializable;// 使用双重校验锁方式实现单例public class Singleton implements Serializable {private volatile static Singleton singleton;private Singleton (){}public static Singleton getSingleton() {if (singleton null) {synchronized (Singleton.class) {if (singleton null) {singleton new Singleton();}}}return singleton;}private Object readResolve() {return singleton;} }还是运行以下测试类 package com.yangxiaoyuan;import java.io.*;public class SerializableDemo1 {//为了便于理解忽略关闭流操作及删除文件操作。真正编码时千万不要忘记//Exception直接抛出public static void main(Stringl] args) throws IOException, ClassNotFoundException {//Write Obj to fileObjectOutputStream oos new ObiectOutputStream(new File0utputstream(tempFile)):oos.writeObject(Singleton.getSingleton());//Read Obj from fileFile file new File(tempFile);ObjectInputStream ois new ObjectInputStream(new FileInputStream(file));Singleton newInstance (Singleton) ois.readObject();//判断是否是同一个对象System.out.println(newInstance Singleton.getSingleton());} }//true本次输出结果为true。具体原理我们回过头继续分析code 3中的第二段代码: 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) {handles .setObject(passHandle, obj rep);} }hasReadResolveMethod :如果实现了serializable 或者 externalizable接口的类中包含 readResolve 则返回true。 invokeReadResolve :通过反射的方式调用要被反序列化的类的readResolve方法。 所以原理也就清楚了只要在Singleton中定义readResolve方法并在该方法中指定要返回的对象的生成策略就可可以防止单例被破坏。
http://www.w-s-a.com/news/446701/

相关文章:

  • 电商网站前端制作分工网站怎做百度代码统计
  • 免费的html大作业网站网站开发心得500字
  • 临时工找工作网站做美缝帮别人做非法网站
  • 深圳网站建设 设计创公司新昌网站开发
  • 唐山教育平台网站建设上海装修网官网
  • 一个公司做多个网站什么行业愿意做网站
  • 成都龙泉建设网站免费域名app官方下载
  • xss网站怎么搭建如何用wordpress站群
  • 怎样做网站外链supercell账号注册网站
  • 阿里巴巴网站是用什么技术做的哪些网站做推广比较好
  • 做网站go和python手机如何创网站
  • 网站开发进修网站做301将重定向到新域名
  • 公司网站开发费用账务处理ucenter wordpress
  • 六站合一的优势少儿编程机构
  • 软件开发与网站开发学做美食网站哪个好
  • 网站搜索 收录优化百度推广页面投放
  • 响应式网站的优点浙江省网站域名备案
  • 网站安全 扫描深圳被点名批评
  • 在哪个网站可以一对一做汉教网站优化策略
  • 龙岩做网站的顺企网宁波网站建设
  • 昆山网站建设河北连锁餐厅vi设计公司
  • 新蔡县住房和城乡建设局网站南昌租房网地宝网
  • 南宁做网站费用iis编辑网站绑定
  • 家用宽带做网站服务器建网站费用明细
  • 电商 网站 降低 跳出率 措施 效果书画院网站模板
  • 兰州移动官网网站建设上海工商网上公示系统
  • 在招聘网站里做电话销售免费空间可以上传网站吗
  • 梅州建站怎么做中国建设银行官网下载
  • 网站静态化设计广州网站备案方案
  • 西安网络技术有限公司网站扬中网站建设方案