本文在文章底部有配套学习视频
前言
我们上面分析了tomcat通过打破双亲委派机制实现了隔离性。那我们自己要怎么实现呐。
一、如何打破双亲委派机制
那我们分析下我们这个MyClassLoaderTest这个加载类的过程:
(1)从main的classLoader.loadClass()进行加载我们指定的类。
Class clazz = classLoader.loadClass("com.kfit.jvm.User1");System.out.println(clazz.getClassLoader().getClass().getName());
(2)loadClass调用的是父类的Classload.loadClass(name,resolve):
protected Class> loadClass(String name, boolean resolve) throws ClassNotFoundException{ synchronized (getClassLoadingLock(name)) { // First, check if the class has already been loaded Class> c = findLoadedClass(name); if (c == null) { long t0 = System.nanoTime(); try { if (parent != null) { c = parent.loadClass(name, false); } else { c = findBootstrapClassOrNull(name); } } catch (ClassNotFoundException e) { // ClassNotFoundException thrown if class not found // from the non-null parent class loader } if (c == null) { // If still not found, then invoke findClass in order // to find the class. long t1 = System.nanoTime(); c = findClass(name); // this is the defining class loader; record the stats sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0); sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1); sun.misc.PerfCounter.getFindClasses().increment(); } } if (resolve) { resolveClass(c); } return c; }}
这里的代码关注如果c=null的时候,就会使用parent的loadClass(),如果最终parent为null的话,那么就使用bootstrapclass loader。
MyClassLoaderTest的的parent会是哪个呐?
大家可以使用debug下,可以看到是ExtClassLoader:
AppClassLoader在去找父类ExtClassLoader:
这个就是我们之前讲过的双亲委派加载机制。
特别注意:在启动的时候,会先执行加载AppClassLoader去加载jvm核心的一些类库,所以debug的时候,要注意观察当前使用的是哪个类加载器,加载的哪个类。
通过上面的分析如果我们要打破双亲委派机制,那么可以重写loadClass()方法。
二、自定义加载器打破双亲委派机制
我们来看下MyClassLoaderTest2,我们通过重写loadClass()打破了双亲委派机制。
protected Class> loadClass(String name, boolean resolve) throws ClassNotFoundException { synchronized (getClassLoadingLock(name)) { // First, check if the class has already been loaded Class> c = findLoadedClass(name); if (c == null) { long t0 = System.nanoTime(); //需要系统类从系统类进行加载. if("java.lang.Object".equals(name)){ Class> clazz = null; ClassLoader system = getSystemClassLoader(); try { c = system.loadClass(name); } catch (Exception e) { // ignore } } //从自己的类加载进行加载. if (c == null) { // If still not found, then invoke findClass in order // to find the class. long t1 = System.nanoTime(); c = findClass(name); // this is the defining class loader; record the stats sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0); sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1); sun.misc.PerfCounter.getFindClasses().increment(); } } if (resolve) { resolveClass(c); } return c; } }}
运行看下结果:
使用了我们自己定义的类加载,但是好像也不能看出打破了双亲加载呐?可以作如下测试:
1)在我们的应用中复制一个com.kfit.jvm.User1的类,(1.1)然后运行,发现还是使用的: MyClassLoaderTest2$MyClassLoader(1.2)注释掉我们的上面的loadClass代码,在运行,那么结果是:Launcher$AppClassLoader
(2)尝试去加载:java.lang.String:
会报错:
java.lang.SecurityException: Prohibited package name: java.lang
上面的测试说明我们确实打破了双亲委派机制,另外还说明了一点就是对于JDK核心的类是被保护的,所在包是被禁止的。
相关历史文章(阅读本文之前,您可能需要先看下之前的系列?)
JVM内存模型和性能调优:为什么要学习JVM - 第1篇
什么是Java虚拟机【JVM:基础入门】 - 第2篇
一图了解JVM核心组成【JVM:基础入门】 - 第3篇
类加载过程【JVM:类加载机制深度剖析】 - 第4篇
深入理解加载和初始化【JVM:类加载机制深度剖析】 - 第5篇
类加载器【JVM:类加载机制深度剖析】 - 第6篇
双亲委派机制【JVM:类加载机制深度剖析】 - 第7篇
打破双亲委派【JVM:类加载机制深度剖析】 - 第8篇
JVM内存模型和调优实战课程
http://t.cn/A6wWMVqG
点击「阅读原文」快速查看学习:
学习的天平上,你在左盘付出的越多,那么在右盘得到的也会随着你的付出而增多。致敬大师,致敬未来的你。