采访者:那您今天详细谈谈家长委托机制吧?候选人:嗯,好的。考生:上次说到:class文件是通过“类加载器”加载到JVM的,而是将请求委托给父加载器完成,依次往上)候选:JDK中的本地方法类一般由根加载器(Bootstrploader)加载,JDK内部实现的扩展类一般为加载由扩展加载器(ExtClassLoader)实现加载,程序中的类文件由系统加载器(AppClassLoader)加载。考生:这个应该很容易理解吧?采访者:麻雀食物(真的)!采访者:接下话题,我想问一下,打破父母委托机制是什么意思?候选人:很容易理解。意思是:只要我加载一个类,按照APPClassLoader->ExtClassLoader->BootStrapClassLoader的顺序找不到,就坏了。候选:因为加载类的核心方法在LoaderClass类的loadClass方法候选(双亲委托机制的核心实现):只要自己自定义一个ClassLoader,重写loadClass方法即可(不开始找根据上面的类加载器),它会破坏双亲委托机制。记者:这么容易?候选人:嗯,就这么简单面试官:那你知道打破双亲委派的场景吗?候选人:最明显的是Tomcat。面试官:说的详细点?考生:一开始部署项目的时候,我们把war包放在tomcat的webapp下面,也就是说一个tomcat可以跑多个web应用(:考生:对吧?面试官:嗯..考生:假设我现在有两个web应用,它们都有一个名为User的类,并且它们的完全限定类名相同,例如com.yyy.User。但是它们的具体实现是不同的候选者:那么Tomcat是如何保证它们不会冲突的呢?考生:答案是Tomcat为每一个Web应用创建一个类加载器实例(WebAppClassLoader)。加载器重写了loadClass方法,先加载当前应用目录下的类。查层(:考生:那么Web应用层级的隔离就是这样实现的。面试官:嗯,你知道Tomcat还有其他的类加载器吗?考生:嗯,知道考生:没有web应用下的所有依赖需要隔离。比如Redis可以在web应用之间共享(如果需要的话),因为如果版本相同,就不需要每个web应用单独加载一份。考生:方法也很简单.tomcat在WebAppClassLoader中添加了一个父类加载器(SharedClassLoader),如果WebAppClassLoader本身不加载某个类,那么就委托SharedClassLoader来加载。考生:(无非是在需要的应用中添加需要共享的类面试官:嗯。web应用还是要共享的,那就有一个类加载器(CommonClassLoader)来加载然后实现共享候选:各个类加载器的加载目录可以在tomcat的catalina.properties配置文件上查看:我画一点Tomcat的类加载结构图,不然有点抽象面试官:嗯,没关系,我明白了,挺有意思的。面试官:对了,我想问一下,你不知道JDBC吗,我听说过,它也破坏了双亲委派模型。你怎么理解的。考生:嗯嗯,这个破不破见仁见智了。考生:JDBC定义接口,具体实现类由各个厂商实现(如MySQL)也由“相同的类加载器”加载。考生:我们在使用JDBC的时候,是通过DriverManager来获取Connection的。DriverManager在java.sql包下,显然是由BootStrap类加载器加载的。考生:我们在使用DriverManager.getConnection()时,得到的一定是Vendor实现的类。考生:但是BootStrapClassLoader可以加载各个厂商实现的类吗?考生:显然不是,这些实现类不在java包中,怎么加载呢?面试官:嗯..考生:DriverManager的解决方案是在DriverManager初始化的时候获取“线程上下文加载器”。》候选项:在获取Connection时,会使用“ThreadContextLoader”来加载Connection,而这里的线程上下文加载器其实就是一个AppClassLoader候选项:所以在获取Connection的时候,先寻找ExtClassLoader和BootStrapClassLoader,但是这两个loader肯定是不加载的,最终会被AppClassLoader加载面试官:嗯..考生:这种情况下,有人认为双亲委派机制被破坏了,因为本来应该由BootStrapClassLoader加载,但是你亲临“线程上下文加载器”,把“类加载器”的候选者改了:有人认为双亲委派机制并没有坏掉,而是改成了“线程上下文加载器”来进行类加载,但它仍然遵守:“依次查找父类加载器进行加载,找不到时自己加载”。相信“原则”没有改变。面试官:然后我明白了这篇文章的总结:前置知识:JDK中默认的类加载器有3种:AppClassLoader、ExtClassLoader、BootStrapClassLoader。AppClassLoader的父加载器是ExtClassLoader,ExtClassLoader的父加载器是BootStrapClassLoader。这里的父子关系不是通过继承来实现的,而是通过组合来实现的。什么是双亲委托机制:在加载过程中,加载器先将类交给父类加载器加载,如果父类加载器找不到,则自己加载。双亲委托机制的目的:防止同一个字节码在内存中被多次复制(安全)类加载规则:如果一个类被类加载器A加载,那么这个类的依赖类也被“同一个类装载机”。如何打破双亲委托机制:自定义ClassLoader,重写loadClass方法(只要不上传到父加载器依次加载,就会打破双亲委托机制)打破双亲委托机制案例:TomcatforWeb应用类之间的隔离,为每个应用创建一个WebAppClassLoader类加载器。为了在Web应用程序类之间共享,使用ShareClassLoader作为WebAppClassLoader的父类加载器。如果找不到WebAppClassLoader加载器,请尝试使用ShareClassLoader加载它。对于Tomcat本身和Web应用程序的类隔离,使用CatalinaClassLoader类加载器进行隔离,CatalinaClassLoader加载Tomcat自身的类供Tomcat和Web应用程序类共享,使用CommonClassLoader作为CatalinaClassLoader的父类加载器和ShareClassLoader.properties来配置线程上下文加载器:由于类加载的规则,很可能父加载器在加载时依赖了子加载器的类,导致无法加载成功(BootStrapClassLoader无法加载第三方库的类),所以有要加载的“线程上下文加载器”。欢迎关注我的微信公众号【Java3y】聊聊Java面试,在线面试官系列持续更新中!【在线面试官-手机版】系列,每周两篇,持续更新中!【在线面试官-电脑】系列每周两篇持续更新中!原创不易!!一连求三!!
