Java实现的自定义类加载器示例
本文实例讲述了Java实现的自定义类加载器。分享给大家供大家参考,具体如下:
一点睛
1ClassLoader类有如下两个关键方法:
loadClass(Stringname,booleanresolve):该方法为ClassLoader的入口点,根据指定的二进制名称来加载类,系统就是调用ClassLoader的该方法来获取指定类对应的Class对象。
findClass(Stringname):根据二进制名称来查找类。
如果需要实现自定义的ClassLoader,可以通过重写以上两个方法来实现,当然我们推荐重写findClass()方法,而不是重写loadClass()方法。
2自定义类加载器常用功能
执行代码前自动验证数字签名。
根据用户提供的密码解密代码,从而可以实现代码混淆器来避免反编译class文件。
根据用户需求来动态地加载类。
根据应用需求把其他数据以字节码的形式加载到应用中。
二实战
1CompileClassLoader.java
importjava.io.*; importjava.lang.reflect.*; publicclassCompileClassLoaderextendsClassLoader { //读取一个文件的内容 privatebyte[]getBytes(Stringfilename) throwsIOException { Filefile=newFile(filename); longlen=file.length(); byte[]raw=newbyte[(int)len]; try( FileInputStreamfin=newFileInputStream(file)) { //一次读取class文件的全部二进制数据 intr=fin.read(raw); if(r!=len) thrownewIOException("无法读取全部文件:" +r+"!="+len); returnraw; } } //定义编译指定Java文件的方法 privatebooleancompile(StringjavaFile) throwsIOException { System.out.println("CompileClassLoader:正在编译" +javaFile+"..."); //调用系统的javac命令 Processp=Runtime.getRuntime().exec("javac"+javaFile); try { //其他线程都等待这个线程完成 p.waitFor(); } catch(InterruptedExceptionie) { System.out.println(ie); } //获取javac线程的退出值 intret=p.exitValue(); //返回编译是否成功 returnret==0; } //重写ClassLoader的findClass方法 protectedClass>findClass(Stringname) throwsClassNotFoundException { Classclazz=null; //将包路径中的点(.)替换成斜线(/)。 StringfileStub=name.replace(".","/"); StringjavaFilename=fileStub+".java"; StringclassFilename=fileStub+".class"; FilejavaFile=newFile(javaFilename); FileclassFile=newFile(classFilename); //当指定Java源文件存在,且class文件不存在、或者Java源文件 //的修改时间比class文件修改时间更晚,重新编译 if(javaFile.exists()&&(!classFile.exists() ||javaFile.lastModified()>classFile.lastModified())) { try { //如果编译失败,或者该Class文件不存在 if(!compile(javaFilename)||!classFile.exists()) { thrownewClassNotFoundException( "ClassNotFoundExcetpion:"+javaFilename); } } catch(IOExceptionex) { ex.printStackTrace(); } } //如果class文件存在,系统负责将该文件转换成Class对象 if(classFile.exists()) { try { //将class文件的二进制数据读入数组 byte[]raw=getBytes(classFilename); //调用ClassLoader的defineClass方法将二进制数据转换成Class对象 clazz=defineClass(name,raw,0,raw.length); } catch(IOExceptionie) { ie.printStackTrace(); } } //如果clazz为null,表明加载失败,则抛出异常 if(clazz==null) { thrownewClassNotFoundException(name); } returnclazz; } //定义一个主方法 publicstaticvoidmain(String[]args)throwsException { //如果运行该程序时没有参数,即没有目标类 if(args.length<1) { System.out.println("缺少目标类,请按如下格式运行Java源文件:"); System.out.println("javaCompileClassLoaderClassName"); } //第一个参数是需要运行的类 StringprogClass=args[0]; //剩下的参数将作为运行目标类时的参数, //将这些参数复制到一个新数组中 String[]progArgs=newString[args.length-1]; System.arraycopy(args,1,progArgs ,0,progArgs.length); CompileClassLoaderccl=newCompileClassLoader(); //加载需要运行的类 Class>clazz=ccl.loadClass(progClass); //获取需要运行的类的主方法 Methodmain=clazz.getMethod("main",(newString[0]).getClass()); Object[]argsArray={progArgs}; main.invoke(null,argsArray); } }
2Hello.java
publicclassHello { publicstaticvoidmain(String[]args) { for(Stringarg:args) { System.out.println("运行Hello的参数:"+arg); } } }
3运行
E:\Java\疯狂java讲义\codes\18\18.2>javaCompileClassLoaderHello自定义加载器
CompileClassLoader:正在编译Hello.java...
运行Hello的参数:自定义加载器
更多java相关内容感兴趣的读者可查看本站专题:《Java面向对象程序设计入门与进阶教程》、《Java数据结构与算法教程》、《Java操作DOM节点技巧总结》、《Java文件与目录操作技巧汇总》和《Java缓存操作技巧汇总》
希望本文所述对大家java程序设计有所帮助。