自定义类加载器案例

160 阅读2分钟

自定义类加载器,加载指定路径在D盘下的lib文件夹下的类。

步骤:

  1. 新建一个需要被加载的类Test.jave

  2. 编译Test.jave到指定lib目录

  3. 自定义类加载器HeroClassLoader继承ClassLoader:

  • 重写findClass()方法
  • 调用defineClass()方法
  1. 测试自定义类加载器

实现: (1)新建一个 Test.java 类,代码如下:

package com.hero.jvm.classloader;
public class Test {
    public void say(){
        System.out.println("Hello HeroClassLoader");
    }
}

(2)使用 javac Test.java 命令,将生成的 Test.class 文件放到 D:/lib/com/hero/jvm/classloader 文件夹下。 (3)自定义类加载器,代码如下:

package com.hero.jvm.classloader;
import java.io.*;
public class HeroClassLoader extends ClassLoader {
    private String classpath;
    public HeroClassLoader(String classpath) {
        this.classpath = classpath;
	}
	@Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
		try { 
		//输入流,通过类的全限定名称加载文件到字节数组 
		byte[] classDate = getData(name);
		if (classDate != null) {
		//defineClass方法将字节数组数据 转为 字节码对象
                return defineClass(name, classDate, 0, classDate.length);
        }
    } catch (IOException e) {
            e.printStackTrace();
	}
    	return super.findClass(name);
	}
	//加载类的字节码数据
	private byte[] getData(String className) throws IOException {
       String path = classpath + File.separatorChar +
                className.replace('.', File.separatorChar) + ".class";
        try (InputStream in = new FileInputStream(path);
             ByteArrayOutputStream out = new ByteArrayOutputStream()) {
            byte[] buffer = new byte[2048];
            int len = 0;
            while ((len = in.read(buffer)) != -1) {
                out.write(buffer, 0, len);
            }
            return out.toByteArray();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        return null;
    }
}

有时候我们会有加载同名的类的需求,这是我们就需要打破双亲委派机制,需求自己写一个类加载器满足,首先创建一个自定义类加载器继承ClassLoader并重写findClass和loadClass方法:

public class CustomClassLoader extends ClassLoader{
    private String classPath;
    public CustomClassLoader(String classPath){
        this.classPath=classPath;
    }

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        byte[] bytes=null;
        int len=0;
        //找到要加载的类的class文件路径,并读入字节码
        try(FileInputStream fis=new FileInputStream(classPath+"/"+name.replace(".","/")+".class")){
            len=fis.available();
            bytes=new byte[len];
            fis.read(bytes);
        }catch (Exception e){
            e.printStackTrace();
        }
        //调用本地方法加载
        return defineClass(name, bytes,0, len);
    }

    @Override
    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 still not found, then invoke findClass in order
                // to find the class.
                long t1 = System.nanoTime();
                //如果是要自己加载的类就直接自己加载,打破双亲委派,如果是其他被引用到的或父类,则让parent加载
                if(name.endsWith("xxx")){
                    c = findClass(name);
                }else{
                    c=this.getParent().loadClass(name);//注意这里不能写super.loadClass,否侧会进入调用死循环
                }

                // 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;
        }
    }
}

(4)测试,代码如下:

package com.hero.jvm.classloader;
import java.lang.reflect.Method;
public class TestMyClassLoader {
    public static void main(String []args) throws Exception{
		//自定义类加载器的加载路径
		HeroClassLoader hClassLoader = new HeroClassLoader("D:\\lib"); //包名+类名
		Class c = hClassLoader.loadClass("com.hero.jvm.classloader.Test");
        if(c!=null){
            Object obj=c.newInstance();
            Method method=c.getMethod("say", null);
            method.invoke(obj, null);
            System.out.println(c.getClassLoader().toString());
} }
}

输出结果如下:在这里插入图片描述