类加载器顺序-另一种绕开双亲委派的方式(二)通篇改写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父亲
浙公网安备 33010602011771号