目的:可以从文件中读取函数代码,动态的编译代码、加载到内存中
参考链接:https://blog.csdn.net/lmy86263/article/details/59742557
代码附加注释
package jit;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URI;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.tools.DiagnosticCollector;
import javax.tools.FileObject;
import javax.tools.ForwardingJavaFileManager;
import javax.tools.JavaCompiler;
import javax.tools.JavaFileManager;
import javax.tools.JavaFileObject;
import javax.tools.SimpleJavaFileObject;
import javax.tools.ToolProvider;
public class JITtest {
//构建文件链表,保存文件中类名和函数
private static Map<String, JavaFileObject> fileObjects = new ConcurrentHashMap<>();
public static void main( String[] args ) throws IOException {
//读取文本内容
StringBuilder fileTxt = new StringBuilder();
File file = new File("/home/liuzao/fileTest");
try{
//构造一个BufferedReader类来读取文件
BufferedReader br = new BufferedReader(new FileReader(file));
String s = null;
while((s = br.readLine())!=null){
//使用readLine方法,一次读一行并附加换行符
fileTxt.append(s + System.lineSeparator());
}
br.close();
}catch(Exception e){
e.printStackTrace();
}
//构建函数
String codeStart = "import jit.*;\n" +
"public class Man{\n" +
"public void hello(){\n" +
"helloworld hello = new helloworld();\n" ;
String codeUser = fileTxt.toString();
String codeEnd = "}\n" +
"}";
String code = codeStart + codeUser +codeEnd;
//获取JavaCompiler,JDK提供的java编译器,如果没有提供编译器,则返回null;
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
//工具的诊断的接口
DiagnosticCollector<JavaFileObject> collector = new DiagnosticCollector<>();
//获取java文件管理类
JavaFileManager javaFileManager = new MyJavaFileManager(compiler.getStandardFileManager(collector, null, null));
//设置编译参数
List<String> options = new ArrayList<>();
options.add("-target");
options.add("1.8");
//正则表达是提取类名字
Pattern CLASS_PATTERN = Pattern.compile("class\\s+([$_a-zA-Z][$_a-zA-Z0-9]*)\\s*");
Matcher matcher = CLASS_PATTERN.matcher(code);
String cls;
if(matcher.find()){
cls = matcher.group(1);
} else {
throw new IllegalArgumentException("No such class name in " + code);
}
//所有超级接口
JavaFileObject javaFileObject = new MyJavaFileObject(cls, code);
// 获取编译任务
//在其他实例都已经准备完毕后, 构建编译任务
Boolean result = compiler.getTask(null, javaFileManager, collector, options, null, Arrays.asList(javaFileObject)).call();
//获取类加载器
ClassLoader classloader = new MyClassLoader();
//加载类
Class<?> clazz = null;
try {
clazz = classloader.loadClass(cls);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
//调用方法名称
Method method = null;
try {
method = clazz.getMethod("hello");
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
//调用方法
try {
method.invoke(clazz.newInstance());
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
}
/*
//获取类中方法并反射使用方法
Method[] method = clazz.getDeclaredMethods();
try {
if(method[0].getName().equals("hello"))
{
method[0].invoke(clazz.newInstance());
}
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException
| InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
*/
}
/**
* 编译代码并加载类
* @author liuzao
*
*/
public static class MyClassLoader extends ClassLoader {
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
JavaFileObject fileObject = fileObjects.get(name);
if(fileObject != null){
byte[] bytes = ((MyJavaFileObject)fileObject).getCompiledBytes();
return defineClass(name, bytes, 0, bytes.length);
} try{
return ClassLoader.getSystemClassLoader().loadClass(name);
} catch (Exception e) {
return super.findClass(name);
}
}
}
public static class MyJavaFileObject extends SimpleJavaFileObject {
private String source;
private ByteArrayOutputStream outPutStream;
// 该构造器用来输入源代码
public MyJavaFileObject(String name, String source) {
// 1、先初始化父类,由于该URI是通过类名来完成的,必须以.java结尾。
// 2、如果是一个真实的路径,比如是file:///test/demo/Hello.java则不需要特别加.java
// 3、这里加的String:///并不是一个真正的URL的schema, 只是为了区分来源
super(URI.create("String:///" + name + Kind.SOURCE.extension), Kind.SOURCE);
this.source = source;
}
// 该构造器用来输出字节码
public MyJavaFileObject(String name, Kind kind){
super(URI.create("String:///" + name + kind.extension), kind);
source = null;
}
@Override
//调用ClientCodeWrapper$WrappedFileObject对象中的filename.getCharContent(false)方法来读取要编译的源码
public CharSequence getCharContent(boolean ignoreEncodingErrors){
if(source == null){ throw new IllegalArgumentException("source == null");
}
return source;
}
@Override public OutputStream openOutputStream() throws IOException {
outPutStream = new ByteArrayOutputStream();
return outPutStream;
}
// 获取编译成功的字节码byte[]
public byte[] getCompiledBytes(){
return outPutStream.toByteArray();
}
}
public static class MyJavaFileManager extends ForwardingJavaFileManager<JavaFileManager> {
protected MyJavaFileManager(JavaFileManager fileManager) {
super(fileManager);
}
@Override public JavaFileObject getJavaFileForInput(Location location, String className, JavaFileObject.Kind kind) throws IOException {
JavaFileObject javaFileObject = fileObjects.get(className);
if(javaFileObject == null){
super.getJavaFileForInput(location, className, kind);
}
return javaFileObject;
}
@Override
public JavaFileObject getJavaFileForOutput(Location location, String qualifiedClassName, JavaFileObject.Kind kind, FileObject sibling) throws IOException {
JavaFileObject javaFileObject = new MyJavaFileObject(qualifiedClassName, kind);
fileObjects.put(qualifiedClassName, javaFileObject);
return javaFileObject;
}
}
}