自定义类加载器|打破JVM双亲委派机制

上一章什么是JVM双亲委派机制

本章简单说明一下怎么去打破jvm的双亲委派机制

jvm的双亲委派机制主要核心方法有两个
1: loadClass
决定有哪个类加载器去加载文件,之后调用findClass
2: findClass
扫描包,解析class

知道核心方法后,从这两个方法入手
首先这两个方法都是在ClassLoader这个文件中并且都是可以重写的
自定义类加载器|打破JVM双亲委派机制_第1张图片
自定义类加载器|打破JVM双亲委派机制_第2张图片
那么就可以继承ClassLoader这个类,重写其中的两个方法
代码如下:

package com.example.demo.launcher;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
 * 继承classLoader 实现两个最重要的方法loadClass、findClass,
 * loadClass 双亲委派的核心逻辑
 * findClass 扫描文件逻辑
 */
public class MyClassloader extends ClassLoader {

    String path;
    public MyClassloader(String path) {
        this.path = path;
    }

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        String loadPath = name.replace('.', '/').concat(".class");
        try {
            FileInputStream inputStream = new FileInputStream(path+loadPath);
            int len = inputStream.available();
            byte[] data = new byte[len];
            inputStream.read(data);
            inputStream.close();

            return super.defineClass(name, data, 0, len);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public Class<?> loadClass(String name) throws ClassNotFoundException {
        if (name.startsWith("com.example.demo.launcher.User")) {
            return findClass(name);
        }
        return super.loadClass(name);
    }
    
}

第一步重写loadClass,里面加入自定义的逻辑,如果条件满足执行自定义的方法,如果条件不满足,执行原来的loadClass双亲委派的逻辑。
第二步重写findClass,将class文件读取出来后复用父类中已有的解析类的方法。
写一个main方法测试一下:

package com.example.demo.launcher;

public class User {

    public void sout() {
        System.out.println("加载完成");
        System.out.println("classLoader: " + this.getClass().getClassLoader());
    }

}

public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException {
		// 传入文件路径
        MyClassloader classloader = new MyClassloader("/Users/zhouzhou/work/");
        Class<?> aClass = classloader.loadClass("com.example.demo.launcher.User");
        Object instance = aClass.newInstance();
        Method method = aClass.getDeclaredMethod("sout", null);
        method.invoke(instance, null);
    }

运行结果:
自定义类加载器|打破JVM双亲委派机制_第3张图片
可以看到User类的类加载器是MyClassLoader。

总结:
通过继承ClassLoader重写loadClass和findClass在不修改双亲委派的基础上实现自定义类加载器。
应用场景比如可以用在tomcat,tomcat加载目录下不同的war,每个war包都是通过一个自定义类加载器去加载的,war包与war包之间具有个隔离性,除了加载本项目中已有class也可以加载一些非标准途径的字节码文件等等。

留下人生足迹,一步一个脚印

你可能感兴趣的:(jvm,java,java)