分享

通过自定义类加载器来验证双亲委托机制

 IT乐知 2020-05-22

上一篇文章我们知道了类加载器通过组合方式实现了双亲委托,那么类又是如何具体加载的呢?

类加载过程

         回顾下类加载的源码,如下图:

         上一篇文章中自定义的类加载器直接重写了loadClass,打乱了类加载的双亲委托机制,今天需要在不破坏这个机制下自定义!

         从源码中可以看出如果在parent最终不能加载的情况下,会来到第3步由当前加载器来加载,而第3步最关键的代码就是“ c = findClass(name)”。我们先找到应用类加载器Launcher.AppClassLoader并没有findClass(name)方法,不过它的父类URLClassLoader实现了findClass方法,方法代码如下图:

        

         可以看到这个方法在获取要加载类的正真文件,继续跟definClass方法最后会调用ClassLoader.defineClass,在这个方法里面会调用一个defineClass1的本地方法!

自定义类加载器

         从以上分析出我们如果想自定义一个类加载器,同时不破坏双亲委托机制,最关键的是重写findClass方法,所以我们就可以自定义实现类加载器了,代码如下图:

        

         自定义的classLoader给他新增了一个名称属性,并且重写了findClass,同时在findClass方法第一行打印了类加载名称和加载的类名称。

         写一个测试方法并运行,运行结果如下图:

         4运行

         根据打印结果可以判断并没有运行findClass方法,这是什么原因呢?

         在自定义的类加载器中构造函数没有显示的执行super()就会默认执行父类的默认构造函数,也就是ClassLoader的默认构造函数,它设置的parent是AppClassLoader

         而我们加载的类“com.dggcc.test.classload.ClassLoadTest”在当前工程下,是可以被AppClassLoader所加载的,所以最终并不会执行MyClassLoader的findClass方法

         对类加载器进行改造,使他去加载指定文件夹下的文件,改造后代码如下图:

         5改造后

         在加载器中添加一个属性path,同时查找class文件的时候只在这个文件下加载,测试代码如下图:

        

         首先要把ClassLoadTest.class移到你想加载的路径下,然后要把把项目下对应的ClassLoadTest.class文件删除,否则在加载的时候AppClassLoader还是能找到“com.dggcc.test.classload.ClassLoadTest”对应的class文件,能够加载成功。删除后由于系统自带的加载器都不能加载这个类,最终由我们自定义的类加载加载,从打印结果可以验证我们的结论!

测试验证结论

         通过自定义类加载我们就可以很方便的验证之前的一些结论,测试代码如下图:

         7复杂结果

         可以看到myclassLoad1对同一个类加载2次,但是真正只加载了一次,并且根据类的hashCode也可以看出来是同一个class对象。而如果再次new一个myclassLoad2出来对同一个class文件加载,就再次加载了一次,并且hashCode也不同不是同一个class对象!

         可以得出结论:同一个类只会被同一个类加载器加载一次,不同的类加载器加载同一个class文件加载出来的class对象也不相同!

         我们对代码再次改造进行测试,改造代码如下图:

        

         新建了一个构造函数用来设置parent属性,通过结果可以看到类只被加载了一次,这是因为myclassLoad1作为了myclassLoad2的parent。所以myclassLoad2在加载类的时候会去myclassLoad1找是否加载。如果加载了myclassLoad2就不会再加载了!

         如果在myclassLoad2之前不加载类,测试代码如下图:

         9双亲委托

         可以看到正真加载类的还是myclassLoad1,也就是双亲委托机制!

总结

         结合上一篇我们知道重写loadClass方法可能会破坏双亲委托机制,而只重写findClass则不会,同时可以实现去加载其他地方的class文件。

         通过自定义类加载我们再次验证了类的加载机制,同一个类只会被同一个类加载器加载一次,不同的类加载器加载同一个class文件加载出来的class对象也不相同! 并且再次验证了双亲委托加载类。

Java程序员日常学习笔记,如理解有误欢迎各位交流讨论!

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多