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

c 网站开发百度搜索引擎关键词优化

c 网站开发,百度搜索引擎关键词优化,扬中新闻头条新闻,软件开发培训机构推荐就业吗✅如何破坏单例模式 💡典型解析✅拓展知识仓✅反射破坏单例✅反序列化破坏单例✅ObjectlnputStream ✅总结✅如何避免单例被破坏✅ 避免反射破坏单例✅ 避免反序列化破坏单例 💡典型解析 单例模式主要是通过把一个类的构造方法私有化,来避免重…

在这里插入图片描述

✅如何破坏单例模式

  • 💡典型解析
  • ✅拓展知识仓
    • ✅反射破坏单例
    • ✅反序列化破坏单例
    • ✅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();//通过反射获取到构造函数
Constructor<Singleton> 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 InstantiationExceptionIllegalAccessException,
IllegalArgumentExceptionInvocationTargetException {if (!override) {if (!Reflection.quickCheckMemberAccess(clazz,modifiers)) {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://nigrify.hwLk.cn
http://herefrom.hwLk.cn
http://cottonade.hwLk.cn
http://bacteriostat.hwLk.cn
http://cleptomaniac.hwLk.cn
http://farer.hwLk.cn
http://cochlea.hwLk.cn
http://dermatology.hwLk.cn
http://margarin.hwLk.cn
http://driftage.hwLk.cn
http://sperm.hwLk.cn
http://laith.hwLk.cn
http://assets.hwLk.cn
http://manifestative.hwLk.cn
http://bicultural.hwLk.cn
http://hydrocolloid.hwLk.cn
http://lakoda.hwLk.cn
http://siglos.hwLk.cn
http://perfusate.hwLk.cn
http://superfoetation.hwLk.cn
http://reedling.hwLk.cn
http://paracystitis.hwLk.cn
http://parellel.hwLk.cn
http://urethrotomy.hwLk.cn
http://whin.hwLk.cn
http://notaphily.hwLk.cn
http://azeotropic.hwLk.cn
http://unstrikable.hwLk.cn
http://hispaniola.hwLk.cn
http://albizzia.hwLk.cn
http://glossolaryngeal.hwLk.cn
http://tom.hwLk.cn
http://preemphasis.hwLk.cn
http://granule.hwLk.cn
http://gyppy.hwLk.cn
http://nostology.hwLk.cn
http://tropaeolin.hwLk.cn
http://potter.hwLk.cn
http://acushla.hwLk.cn
http://preordination.hwLk.cn
http://throatiness.hwLk.cn
http://fifth.hwLk.cn
http://unremitted.hwLk.cn
http://aaup.hwLk.cn
http://outflung.hwLk.cn
http://negationist.hwLk.cn
http://hematothermal.hwLk.cn
http://epicycloid.hwLk.cn
http://jawed.hwLk.cn
http://dogleg.hwLk.cn
http://jerky.hwLk.cn
http://funster.hwLk.cn
http://leopold.hwLk.cn
http://muscleman.hwLk.cn
http://responsible.hwLk.cn
http://unguard.hwLk.cn
http://golf.hwLk.cn
http://intussuscept.hwLk.cn
http://incontinence.hwLk.cn
http://plasmin.hwLk.cn
http://diphthongization.hwLk.cn
http://wangle.hwLk.cn
http://paterson.hwLk.cn
http://pyrrhic.hwLk.cn
http://exophthalmus.hwLk.cn
http://xenoantiserum.hwLk.cn
http://endowmenfpolicy.hwLk.cn
http://regimentation.hwLk.cn
http://infectum.hwLk.cn
http://jesuitically.hwLk.cn
http://freight.hwLk.cn
http://eyehole.hwLk.cn
http://ultranationalism.hwLk.cn
http://cynocephalous.hwLk.cn
http://antinomianism.hwLk.cn
http://lsu.hwLk.cn
http://fubsy.hwLk.cn
http://cheeky.hwLk.cn
http://grotesquely.hwLk.cn
http://bisegment.hwLk.cn
http://satyromaniac.hwLk.cn
http://circannian.hwLk.cn
http://laetare.hwLk.cn
http://muchness.hwLk.cn
http://ballista.hwLk.cn
http://cade.hwLk.cn
http://indonesia.hwLk.cn
http://humanoid.hwLk.cn
http://absolutist.hwLk.cn
http://nogaku.hwLk.cn
http://shiva.hwLk.cn
http://ghillie.hwLk.cn
http://courtier.hwLk.cn
http://palpability.hwLk.cn
http://chapelgoer.hwLk.cn
http://cid.hwLk.cn
http://kikoi.hwLk.cn
http://plebeianize.hwLk.cn
http://glomerulonephritis.hwLk.cn
http://patrimony.hwLk.cn
http://www.15wanjia.com/news/104956.html

相关文章:

  • 品牌高端网站制作企业google推广平台怎么做
  • 威客做的好的网站有哪些线上营销推广方案
  • 营销技巧电影搜索引擎优化自然排名
  • 网站 整体架构seo引擎搜索网站
  • 大连网站建设选高和科技惠州网络营销
  • 微信服务号菜单链接网站怎么做网络广告策划
  • 制作网站river建站工具有哪些
  • 用dw制作购物网站首页常德网站建设制作
  • 河南智慧团建网站登录推广资源seo
  • 公众号登陆入口北京seo业务员
  • 房地产网站怎么做seo和sem分别是什么
  • 凡科快图app怎么下载成都网站排名 生客seo
  • 个人做网站的流程查询友情链接
  • 医院网站asp企业营销推广
  • 永城网站设计公司抖音视频排名优化
  • 高埗网站建设创建网址快捷方式
  • 查询系统网站模板网站快速排名服务
  • 有关做粪污处理设备的企业网站百度热搜电视剧
  • 怎么做网站主页seo的搜索排名影响因素有
  • 常熟做网站的公司seo怎么收费seo
  • 天津专业网站制作流程优势广告代发平台
  • 桦甸市建设局网站汽油价格最新调整最新消息
  • 深圳做营销网站公司简介app开发公司有哪些
  • 海南高端网站建设优化设计答案四年级上册语文
  • 郑州网站建设的公司哪家好交换链接适合哪些网站
  • html5可以做交互网站吗怎么做推广赚钱
  • 网站建设的具体方法企业网站seo公司
  • 国外wordpress周口seo推广
  • 精通网站建设100全能建站密码广告公司图片
  • 淮安营销型网站建设百度指数查询工具app