自定义类加载器
loadClass方法实现了双亲委派模型。
- 首先,检查一下指定名称的类是否已经加载过,如果加载过了,就不需要再加载,直接返回。
- 如果此类没有加载过,那么,再判断一下是否有父加载器;如果有父加载器,则由父加载器加载(即调用parent.loadClass(name, false); ).或者是调用bootstrap类加载器来加载。
- 如果父加载器及bootstrap类加载器都没有找到指定的类,那么调用当前类加载器的findClass方法来完成类加载。
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;
}
}
【自定义类加载器】我们重写findClass方法。
注意在运行的时候,复制项目target中的com.qunar.LoadTest的class文件。拷贝到根目录下,linux下即/com/qunar/LoadTest。然后删除项目目录下的该文件。
因为虽然我们重写了findClass加载地址,但是根据双亲委派模型,父加载器appclassloader会在项目下查找,如果找到对应class就会加载,自定义的类加载器就没用了。当然如果我们直接掉用findClass方法就会直接加载,不会向上查找了。
import java.io.FileInputStream;
import java.lang.reflect.Method;
public class Main {
static class MyClassLoader extends ClassLoader {
private String classPath;
public MyClassLoader(String classPath) {
this.classPath = classPath;
}/**
* 将class文件转换成字节数组
*/
private byte[] loadByte(String name) throws Exception {
name = name.replaceAll("\\.", "/");
FileInputStream fis = new FileInputStream(classPath + "/" + name
+ ".class");
int len = fis.available();
byte[] data = https://www.it610.com/article/new byte[len];
fis.read(data);
fis.close();
return data;
}/**
* 通过类全名找到class文件,转换成字节数组,转化成class对象
*/
@Override
protected Class> findClass(String name) throws ClassNotFoundException {
try {
byte[] data = https://www.it610.com/article/loadByte(name);
return defineClass(name, data, 0, data.length);
} catch (Exception e) {
e.printStackTrace();
throw new ClassNotFoundException();
}
}}public static void main(String args[]) throws Exception {
MyClassLoader classLoader = new MyClassLoader("");
Class clazz = classLoader.loadClass("com.qunar.LoadTest");
Object obj = clazz.newInstance();
Method helloMethod = clazz.getDeclaredMethod("hello", null);
helloMethod.invoke(obj, null);
}}
public class LoadTest {
public void hello() {
System.out.println("恩,是的,我是由 " + getClass().getClassLoader().getClass()
+ " 加载进来的");
}
}
推荐阅读
- JAVA(抽象类与接口的区别&重载与重写&内存泄漏)
- 为什么你的路演总会超时()
- 标签、语法规范、内联框架、超链接、CSS的编写位置、CSS语法、开发工具、块和内联、常用选择器、后代元素选择器、伪类、伪元素。
- SpringBoot调用公共模块的自定义注解失效的解决
- python自定义封装带颜色的logging模块
- thinkphp|thinkphp 3.2 如何调用第三方类库
- 使用composer自动加载类文件
- 一个健康的APP和健全的人格大体类似
- 列出所有自定义的function和view
- 种树郭橐驼传(文言句式+古今异义+词类活用+通假字)