美文网首页
五、ClassLoader双亲委派加载模式

五、ClassLoader双亲委派加载模式

作者: 社会yang | 来源:发表于2019-12-03 09:38 被阅读0次

    类加载器加载的目录

    获取启动类加载器加载的目录 System.getProperty("sun.boot.class.path");

    获取扩展类加载器加载的目录 System.getProperty("java.ext.dirs");

    获取应用类加载器加载的目录 System.getProperty("java.class.path");

    将test.Test2.class移到启动类加载器加载的目录,然后其加载类

    启动类加载器加载目录如下

    通过上述案列可以分析出,test.Test2是由启动类加载器加载的,验证了双亲委派优先父加载器加载

    扩展类加载器加载案列

    通过上述案列得出AESKeyGenerator是由扩展类加载器加载的,手动修改扩展类加载器加载的目录,修改完成后在修改后的目录是找不到AESKeyGenerator,所以会报错

    java -Djava.ext.dirs=./ test.Test19

    将本地目录作为扩展类加载器加载的目录

    类加载器命名空间定义以及举例

    同一个命名空间内的类时相互可见的

    子加载器的命名空间包含所有的父加载器的命名空间。因此由子加载器加载的类可以看见父加载器加载的类。例如系统类加载器加载的类能看见跟类加载器加载的类。

    由父加载器加载的类不能看见子加载器加载的类。

    如果两个加载器之间没有直接或者间接的父子关系,那么它们各自加载的类相互不可见

    上述案列是因为classLoader1与classLoader2的父加载器都为AppClassLoader,所以classLoader1加载完Person后在内存的缓存中是有Person.class的,classLoader2委托AppClassLoader加载的时候直接就从内存中获取Person.class,所以他们是一致的,method方法也是可以执行的

    当删除当前classpath下的Person.class文件,将Person.class文件移到D盘下

    此时当前的classPath下没有Person.class文件,会分别由classLoader1加载器与classLoader2加载器加载,会存在classLoader1加载器的命名空间以及classLoader2加载器的命名空间,根据 如果两个加载器之间没有直接或者间接的父子关系,那么它们各自加载的类相互不可见 的规则那么classLoader1与classLoader2加载的类时相互不可见的也是不相同的,这里会有很有趣的问题  java.lang.ClassCastException: test.Person cannot be cast to test.Person

    修改扩展类加载器加载路劲案列

    修改扩展类加载路劲为当前路径

    执行 java -Djava.ext.dirs=./ test.Test22

    可以发现还是使用AppClassLoader加载的Test22以及Test1

    扩展类加载器不能直接加载.class文件,需要将.class文件打成jar包

    jar cvf test.jar test/Test1.class

    再次执行 ,可以发现Test1是通过扩展类加载器加载的,因为此处只将Test1打成jar包了

    类加载器双亲委派模式的好处

    1. 可以确保java核心库的类型安全: 例如所有的JAVA应用都至少会引用java.lang.Object类,也就是说在jvm的运行期间,java.lang.Object类会被加载到java虚拟机中,如果这个过程是由自己定义的java类加载器完成的,那么很有可能在jvm中存在多个版本的java.lang.Object类,也就是说在jvm的运行期间而这些类之间是相互不兼容的(命名空间不同导致的)。

    借助双亲委派机制,java核心类库的加载必须由启动类加载器加载,从而确保java中使用的核心类库的版本统一,他们之间是相互兼容的

    2. 可以保证java核心类库加载的类不会被自定义类所替代。

    3. 不同类的加载器可以为相同名称的类(binary name)创建额外的命名空间。相同名称的类可以并存与不同命名空间的内存中,不同类加载器加载的类之间是相互不兼容的就相当于在java虚拟机内部创建了一个又一个相互独立并且隔离的的java空间,这类技术在很多框架都得到了使用。

    启动类加载器相关及案列

    在运行期间,一个Java类是由该类的完全限定名(binary name,二进制名)和用于加载该类的定义类加载器(defining loader)所共同决定的。如果同样名字(即相同的限定名)的类是由两个不同的加载类所加载,那么这些类就是不同的,即便.class文件的字节码完全一样,并且从相同的位置加载也是如此。

    在Oracle的Hotspot实现中,系统属性 sun.boot.class.path如果被修改错了,则运行会出错,提示如下错误信息:

    Error occureed during initialization of VM

    java/lang/NoClassDefFoundError: java/lang/Object

    内建于JVM中的启动类加载器会加载java.lang.ClassLoader以及其他的java平台类,当JVM启动时,一块特殊的机器码会运行,它会加载扩展类加载器以及系统类加载器,这块特殊的机器码叫做启动类加载器(BootStrap)。启动类加载器并不是java类,而其他的加载器都是java类,启动类加载器是特定于平台的机器指令,它负责开启整个加载过程

    所有类加载器(除了启动类加载器)都被实现为Java类。不过总归要有一个组件来加载第一个java类加载器,从而让整个加载过程能够顺利进行,加载第一个纯JAVA类加载器就是启动类加载器的职责。

    启动类加载器还会负责加载JRE正常运行时所需的基本组件,这包括java.util与java.lang包中的类等等

    java -Djava.system.class.loader=test.Test16 test.Test23

    相关文章

      网友评论

          本文标题:五、ClassLoader双亲委派加载模式

          本文链接:https://www.haomeiwen.com/subject/ljzxgctx.html