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[]{}); } } 运行结果:
创建自己的类加载器:
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[]{}); } }
运行结果: