“如何破坏双亲委派模型”!
这是一个工作5年的同学去美团面试遇到的面试题。
大家好,我是Mic,咕泡科技联合创始人
下面来分析一下这个问题的考察目的
这是一个偏Java基础的问题,考察3年以上的Java程序员。
这个问题考察目的有两个:
了解求职者对于Java基础的掌握深度,类加载相关知识点挺多的,涉及到类加载器、类的生命周期、JVM的工作原理,掌握这些基础可以快速解决程序中的一些问题,比如加载的类版本错误导致NoSuchMethodException
平时的工作中几乎不会用到类加载器,也不需要涉及到这方面的专业知识,所以这个问题很好的实现了人才能力的筛选
下面来分析一下这个问题的具体背景。
我们自己写的java源文件到最终运行,必须要经过编译和类加载两个阶段。
编译的过程就是把.java文件编译成.class文件。
类加载的过程,就是把class文件装载到JVM内存中,装载完成以后就会得到一个Class对象,我们就可以使用new关键字来实例化这个对象。
而类的加载过程,需要涉及到类加载器。
JVM在运行的时候,会产生3个类加载器,这三个类加载器组成了一个层级关系。
每个类加载器分别去加载不同作用范围的jar包,比如
Bootstrap ClassLoader,主要是负责Java核心类库的加载,也就是 %{JDK_HOME}\lib下的rt.jar、resources.jar等
Extension ClassLoader,主要负责%{JDK_HOME}\lib\ext目录下的jar包和class文件
Application ClassLoader,主要负责当前应用里面的classpath下的所有jar包和类文件
除了系统自己提供的类加载器以外,还可以通过ClassLoader类实现自定义加载器,去满足一些特殊场景的需求。
而双亲模型,就是按照类加载器的层级关系,逐层进行委派。
比如当需要加载一个class文件的时候,首先会把这个class的查询和加载委派给父加载器去执行,如果父加载器都无法加载,再尝试自己来加载这个class。
不过,双亲委派并不是一个强制性的约束模型,我们可以通过一些方式去打破双亲委派模型。
这个打破的意思,就是类加载器可以加载不属于当前作用范围的类,实际上,JVM本身就存在双亲委派被破坏的情况。
第一种情况,双亲委派是在JDK1.2版本发布的,而类加载器和抽象类ClassLoader在JDK1.0就已经存在了,用户可以通过重写ClassLoader里面的loadClass()方法实现自定义类加载,JDK1.2为了向前兼容,所以在设计的时候需要兼容loadClass()重写的实现,导致双亲委派被破坏的情况。
同时,为了避免后续再出现这样的问题,不在提倡重写loadClass()方法,而是使用JDK1.2中ClassLoader中提供了findClass方法来实现符合双亲委派规则的类加载逻辑。
第二种情况,在这个类加载模型中,有可能存在顶层类加载器加载的类,需要调用用户类加载器实现的代码的情况。
比如java.jdbc.Driver接口,它只是一个数据库驱动接口,这个接口是由启动类加载器加载的。
但是java.jdbc.Driver接口的实现是由各大数据库厂商来完成的,既然是自己实现的代码,就应该由应用类加载器来加载。
于是就出现了启动类加载器加载的类要调用应用类加载器加载的实现。
为了解决这个问题,在JVM中引入了线程上下文类加载器,它可以把原本需要启动类加载器加载的类,由应用类加载器进行加载。
除此之外,像Tomcat容器,也存在破坏双亲委派的情况,来实现不同应用之间的资源隔离。
了解了这些背景之后,我们来看看高手该怎么回答。
我知道有两种方式来破坏双亲委派模型
第一种,集成ClassLoader抽象类,重写loadClass方法,在这个方法可以自定义要加载的类使用的类加载器。
第二种,使用线程上下文加载器,可以通过java.lang.Thread类的setContextClassLoader()方法来设置当前类使用的类加载器类型。
好的,大家知道怎么回答这个问题了吗?
今天的视频就到这里结束了,喜欢这个作品的小伙伴记得点赞收藏加关注!!!
另外,我将所有Java面试系列制作成了完整的面试文档。它的便捷之处在于,可以通过检索的方式,找到你想要的面试题,目前已经更新200期,总计超过20W字!