YLLEN

要去看埃菲尔铁塔的顶

欢迎关注本人微博:t.cn/RGSLVUk

Java 自定义 类加载器

自定义类加载器

主要是重写了findClass方法,采用的策略是 读取Class 字节码,

 利用 defineClass()方法 生成Class 对象。

至于 源码 到class 字节码的方法,下面采用运行时调用外部shell来编译

还可以采用  

   内存编译 ( ToolProvider.getSystemJavaCompiler();)方式

自定义类加载器的好处 有很多,比如加密,动态加载字节码,获取校验签名 etc ...


import java.io.File;

import java.io.FileInputStream;

import java.io.IOException;

import java.lang.reflect.InvocationTargetException;

import java.lang.reflect.Method;


public class ComplieClassLoader extends ClassLoader

{

private byte[] getBytes(String filename) throws IOException

{

File file = new File(filename);

long len = file.length();

byte[] raw = new byte[(int)len];


try( FileInputStream fin = new FileInputStream(file);)

{

//读取Class 文件的 全部二进制数据

int r = fin.read(raw);

if(r != len)

throw new IOException("无法读取全部文件" + r + "!= " + len);

return raw;

}

}

private boolean complie(String javaFile) throws IOException

{

System.out.println("ComplieClassLoader :正在编译 " + javaFile + "...");

Process p = Runtime.getRuntime().exec("javac " + javaFile);

try

{

//其他线程等待这个线程

p.waitFor();

}catch(InterruptedException e)

{

System.out.println(e);

}

//获取 javac 的退出值

int ret = p.exitValue();

return ret == 0;

}

//重写findClass方法

protected Class<?> findClass(String name)

throws ClassNotFoundException

{

Class clazz = null;

//包路径中 的 . 替换成 /

String fileStub = name.replace(".", "/");

String javaFilename = fileStub + ".java";

String classFilename = fileStub + ".class";

File javaFile = new File(javaFilename);

File classFile = new File(classFilename);

//当指定 Java 源文件存在,且Class 文件不存在 , 或者 Java 源文件

// 的修改时间比Class 文件的修改时间更晚时,重新编译

if(javaFile.exists() && (!classFile.exists()) ||

javaFile.lastModified() > classFile.lastModified())

{

try

{

if(!complie(javaFilename) || !classFile.exists())

{

throw new ClassNotFoundException(

"ClassNotFoundException:" + javaFilename

);

}

}catch(IOException e)

{

e.printStackTrace();

}

}

//如果class文件存在,系统将class 文件转换成Class 对象

if(classFile.exists())

{

try

{

byte[] raw = getBytes(classFilename);

//调用ClassLoader的defineClass方法将二进制转换成Class对象

clazz = defineClass(name,raw,0,raw.length);

}catch(IOException e)

{

e.printStackTrace();

}

}

if(clazz == null)

{

throw new ClassNotFoundException(name);

}

return clazz;

}

public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException

{

if(args.length < 1)

{

System.out.println("缺少主类,请按格式运行java源文件: ");

System.out.println("java CompileClassLoader ClassName");

return;

}

String progClass = args[0];

// 剩下的参数将作为运行目标类时的参数

// 将这些参数复制到一个新数组中

String[] progArgs  = new String [args.length -1];

System.arraycopy(args, 1, progArgs, 0, progArgs.length);

ComplieClassLoader ccl = new ComplieClassLoader();

//加载需要运行的类

Class <?> clazz = ccl.loadClass(progClass);

Method main = clazz.getMethod("main", (new String[0]).getClass());

Object argsArray[] = {progArgs};

main.invoke(null, argsArray);

}

}


评论

© YLLEN | Powered by LOFTER