类加载器顺序-另一种绕开双亲委派的方式(二)通篇改写loadClass
今天对类加载器顺序-另一种绕开双亲委派的方式中的第2种方式做一个实践,基本与JDBC注册原理与自定义类加载器解决com.cloudera.hive.jdbc41.HS2Driver的加载【重点】,使用resource中的jar包资源作为UrlClassloader(二)同,主要区别在于
这两篇文章侧重于maven仓库没有的包,意味着系统类加载器无法一上来就加载,没有子加载器想要覆盖父加载器的类的背景,故里面用的是改写findClass,因为这些类不在maven中,不涉及到loadClass双亲委派,findClass即可
而今天这个实践,是要实验用子加载器加载同名类覆盖掉父加载同名类的表现,从而打破双亲委派,达到类加载器隔离朴实案例的效果
代码拷贝自使用resource中的jar包资源作为UrlClassloader(二)中2,最主要的两句,@override loadClass + super.loadClass
package lc4; import java.io.*; import java.util.HashMap; import java.util.jar.JarEntry; import java.util.jar.JarInputStream; import static lc4.FuckPreFindClass.doInvoke; /** * https://www.cnblogs.com/silyvin/articles/12423508.html */ public class SafeSon { public static void main(String []f) throws Exception { String dir = "/Users/sunyuming/Documents/tool/jars//MySub-1.0.0-jar-with-dependencies.jar"; InputStream url1 = new FileInputStream(dir); SunLoadClass sunLoadClass = new SunLoadClass(new JarInputStream[]{new JarInputStream(url1)}); Class c1 = sunLoadClass.loadClass("lc4.H"); doInvoke(c1); url1.close(); url1 = new FileInputStream(dir); SunFindClass sunFindClass = new SunFindClass(new JarInputStream[]{new JarInputStream(url1)}); Class c2 = sunFindClass.loadClass("lc4.H"); doInvoke(c2); } private static class SunLoadClass extends ClassLoader { JarInputStream [] list = null; private HashMap<String, byte[]> classes = new HashMap<>(); public SunLoadClass(JarInputStream [] jarInputStream) { this.list = jarInputStream; for(JarInputStream jar : list) { JarEntry entry; try { while ((entry = jar.getNextJarEntry()) != null) { String name = entry.getName(); ByteArrayOutputStream out = new ByteArrayOutputStream(); int len = -1; byte [] tmp = new byte[1024]; while ((len = jar.read(tmp)) != -1) { out.write(tmp, 0, len); } byte[] bytes = out.toByteArray(); classes.put(name, bytes); } } catch (Exception e) { e.printStackTrace(); } } System.out.println("total classes - " + classes.size()); } @Override //protected Class<?> findClass(String name) throws ClassNotFoundException { public Class<?> loadClass(String name) throws ClassNotFoundException { System.out.println("load " + name); try { InputStream in = getResourceAsStream(name.replace('.', '/') + ".class"); ByteArrayOutputStream out = new ByteArrayOutputStream(); int len = -1; byte [] tmp = new byte[1024]; while ((len = in.read(tmp)) != -1) { out.write(tmp, 0, len); } byte[] bytes = out.toByteArray(); /** * 三个类都是475长度 */ return defineClass(name, bytes, 0, bytes.length); } catch (Exception e) { e.printStackTrace(); } // return super.findClass(name); return super.loadClass(name); } @Override public InputStream getResourceAsStream(String name) { System.out.println("getResourceAsStream - " + name); if(classes.containsKey(name)) { byte [] res = classes.get(name); /** * define好了就remove掉,否则占堆 */ classes.remove(name); return new ByteArrayInputStream(res); } System.out.println("getResourceAsStream - error - " + name); return super.getResourceAsStream(name); } } private static class SunFindClass extends ClassLoader { JarInputStream [] list = null; private HashMap<String, byte[]> classes = new HashMap<>(); public SunFindClass(JarInputStream [] jarInputStream) { this.list = jarInputStream; for(JarInputStream jar : list) { JarEntry entry; try { while ((entry = jar.getNextJarEntry()) != null) { String name = entry.getName(); ByteArrayOutputStream out = new ByteArrayOutputStream(); int len = -1; byte [] tmp = new byte[1024]; while ((len = jar.read(tmp)) != -1) { out.write(tmp, 0, len); } byte[] bytes = out.toByteArray(); classes.put(name, bytes); } } catch (Exception e) { e.printStackTrace(); } } System.out.println("total classes - " + classes.size()); } @Override protected Class<?> findClass(String name) throws ClassNotFoundException { System.out.println("find " + name); try { InputStream in = getResourceAsStream(name.replace('.', '/') + ".class"); ByteArrayOutputStream out = new ByteArrayOutputStream(); int len = -1; byte [] tmp = new byte[1024]; while ((len = in.read(tmp)) != -1) { out.write(tmp, 0, len); } byte[] bytes = out.toByteArray(); /** * 三个类都是475长度 */ return defineClass(name, bytes, 0, bytes.length); } catch (Exception e) { e.printStackTrace(); } return super.findClass(name); } @Override public InputStream getResourceAsStream(String name) { System.out.println("getResourceAsStream - " + name); if(classes.containsKey(name)) { byte [] res = classes.get(name); /** * define好了就remove掉,否则占堆 */ classes.remove(name); return new ByteArrayInputStream(res); } System.out.println("getResourceAsStream - error - " + name); return super.getResourceAsStream(name); } } }
total classes - 467
load lc4.H
getResourceAsStream - lc4/H.class
load java.lang.Object
getResourceAsStream - java/lang/Object.class
getResourceAsStream - error - java/lang/Object.class
java.lang.SecurityException: Prohibited package name: java.lang
at java.lang.ClassLoader.preDefineClass(ClassLoader.java:662)
at java.lang.ClassLoader.defineClass(ClassLoader.java:761)
at java.lang.ClassLoader.defineClass(ClassLoader.java:642)
at lc4.SafeSon$SunLoadClass.loadClass(SafeSon.java:76)
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:763)
at java.lang.ClassLoader.defineClass(ClassLoader.java:642)
at lc4.SafeSon$SunLoadClass.loadClass(SafeSon.java:76)
at lc4.SafeSon.main(SafeSon.java:19)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)
load java.lang.System
getResourceAsStream - java/lang/System.class
getResourceAsStream - error - java/lang/System.class
java.lang.SecurityException: Prohibited package name: java.lang
at java.lang.ClassLoader.preDefineClass(ClassLoader.java:662)
at java.lang.ClassLoader.defineClass(ClassLoader.java:761)
at java.lang.ClassLoader.defineClass(ClassLoader.java:642)
at lc4.SafeSon$SunLoadClass.loadClass(SafeSon.java:76)
at lc4.H.print(H.java:9)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at lc4.FuckPreFindClass.doInvoke(FuckPreFindClass.java:64)
at lc4.SafeSon.main(SafeSon.java:20)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)
load java.io.PrintStream
getResourceAsStream - java/io/PrintStream.class
getResourceAsStream - error - java/io/PrintStream.class
java.lang.SecurityException: Prohibited package name: java.io
at java.lang.ClassLoader.preDefineClass(ClassLoader.java:662)
at java.lang.ClassLoader.defineClass(ClassLoader.java:761)
at java.lang.ClassLoader.defineClass(ClassLoader.java:642)
at lc4.SafeSon$SunLoadClass.loadClass(SafeSon.java:76)
at lc4.H.print(H.java:9)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at lc4.FuckPreFindClass.doInvoke(FuckPreFindClass.java:64)
at lc4.SafeSon.main(SafeSon.java:20)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)
H儿子
load lc4.ByW
getResourceAsStream - lc4/ByW.class
ByW儿子
total classes - 467
H父亲 这个地方:系统类加载器直接加载了,都没进自定义加载器findClass和getResourceAsStream
ByW父亲