Java自定义类加载器

通过继承java.lang.ClassLoader可以自定义类加载器。

步骤:

1、继承ClassLoader。

2、读取字节文件到字节数组中。

3、使用defineClass(类名,字节数组,off,length):将字节数组转换为类的Class的实例。 


 

 

准备工作:一个待加载的Hello.class,它的内容为一个main方法,控制台输出一句“hello world!”

通过继承java.lang.ClassLoader可以自定义类加载器。

准备:一个待加载的Hello.class,它的内容为一个main方法,控制台输出一句“hello world!”



 

创建自己的类加载器:

import java.io.*;

public class LrjClassLoader extends ClassLoader{
    private String rootDir;

    /**
     * 构造器:指定类加载的位置
     */
    public LrjClassLoader(String rootDir) {
        this.rootDir = rootDir;
    }

    /**
     * 查找名称为name的类,并且加载它,返回Class对象,
     * @param name
     * @return
     * @throws ClassNotFoundException
     */
    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        Class<?> cls = findLoadedClass(name);

        if(cls!=null){
            return cls;//此类已经被加载过了
        }else {
            ClassLoader parent = this.getParent();
            try {
                cls = parent.loadClass(name);//让父类先加载
            }catch (Exception e){
                System.out.println("父类加载失败....准备自己淦!");
            }
            if(cls!=null){
                return cls;//感谢父类
            }else {
                //mmp,我自己加载
                byte[] classData = getClassDate(name);
                if(classData==null){
                    throw new ClassNotFoundException();//加载失败
                }else {
                    //将字节数组转换为类别 Class的实例。
                    cls = defineClass(name,classData,0,classData.length);
                    return cls;
                }
            }
        }
    }

    /**
     *把类的名字给我,我把它的字节码文件放在字节数组中给你。
     * @param name  类名
     * @return  字节数组:内容为它的class文件
     */
    private byte[] getClassDate(String name){
        String path = rootDir+"/"+name.replace('.','/')+".class";

        try(FileInputStream is = new FileInputStream(path);) {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            byte[] buffer = new byte[1024];
            int len=0;
            while ((len=is.read(buffer))!=-1){
                baos.write(buffer,0,len);
            }
            baos.flush();
            //
            return baos.toByteArray();
        }catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }
}
使用自定义的类加载器:

public class TestClassloader {
    public static void main(String[] args) throws Exception {
        //创建的时候指定加载空间
        LrjClassLoader lc = new LrjClassLoader("d:/my_file");
        //加载此类,获取Class对象
        Class aClass= lc.findClass("lurenjia.test.Hello");

        //运行Hello
        aClass.getMethod("main",String[].class).invoke(null,(Object)new String[]{});
    }
}
运行结果:
查看Hello.java

创建自己的类加载器:

import java.io.*;

public class LrjClassLoader extends ClassLoader{
    private String rootDir;

    /**
     * 构造器:指定类加载的加载位置
     */
    public LrjClassLoader(String rootDir) {
        this.rootDir = rootDir;
    }

    /**
     * 查找名称为name的类,并且加载它,返回Class对象,
     * @param name
     * @return
     * @throws ClassNotFoundException
     */
    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        Class<?> cls = findLoadedClass(name);

        if(cls!=null){
            return cls;//此类已经被加载过了
        }else {
            ClassLoader parent = this.getParent();
            try {
                cls = parent.loadClass(name);//让父类先加载
            }catch (Exception e){
                System.out.println("父类加载失败....准备自己淦!");
            }
            if(cls!=null){
                return cls;//感谢父类
            }else {
                //mmp,我自己加载
                byte[] classData = getClassDate(name);
                if(classData==null){
                    throw new ClassNotFoundException();//加载失败
                }else {
                    //将字节数组转换为类的 Class的实例。
                    cls = defineClass(name,classData,0,classData.length);
                    return cls;
                }
            }
        }
    }

    /**
     *把类的名字给我,我把它的字节码文件放在字节数组中给你。
     * @param name  类名
     * @return  字节数组:内容为它的class文件
     */
    private byte[] getClassDate(String name){
        String path = rootDir+"/"+name.replace('.','/')+".class";

        try(FileInputStream is = new FileInputStream(path);) {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            byte[] buffer = new byte[1024];
            int len=0;
            while ((len=is.read(buffer))!=-1){
                baos.write(buffer,0,len);
            }
            baos.flush();
            //
            return baos.toByteArray();
        }catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }
}

 

使用自定义的类加载器:

public class TestClassloader {
    public static void main(String[] args) throws Exception {
        //创建的时候指定加载空间
        LrjClassLoader lc = new LrjClassLoader("d:/my_file");
        //加载此类,获取Class对象
        Class aClass= lc.findClass("lurenjia.test.Hello");

        //运行Hello
        aClass.getMethod("main",String[].class).invoke(null,(Object)new String[]{});
    }
}

 

运行结果:

posted @ 2022-11-21 22:39  在博客做笔记的路人甲  阅读(1335)  评论(0编辑  收藏  举报