要去看埃菲尔铁塔的顶
欢迎关注本人微博:t.cn/RGSLVUk
自定义类加载器
主要是重写了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);
}
}