码云开源代码:
https://gitee.com/china-bin/vue-onlinecode
原理:
1.利用java里面有JavaComile 可以实现在程序里面编译允许其他的java代码
步骤:
1.利用JavaComile, 将java代码 编译到内存中
2.从内存中根据类名取出此类
3.通过java反射调用此类的方法
详细Demo代码如下:
import com.haiyang.onlinejava.complier.util.ClassClassLoader;
import javax.tools.*;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.lang.reflect.Method;
import java.net.URI;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.FileChannel;
import java.nio.channels.WritableByteChannel;
import java.util.Arrays;
/**
* @author: bin
* @email: 958615915@qq.com
* @create: 2019-08-03
*/
public class TestComiles {
private String javaSource = "class Solution { " +
" public static String sayHello() { return \"hello world\"; } " +
"}";
private String javaSource2 = "class Solution { " +
" public static String sayHello(int i) { return \"hello world\" + i; } " +
"}";
private String className = "Solution";
private String methoName = "sayHello";
// path 是你想把.class 放在哪里的路径,
private String path = "C:\\Users\\bin\\Desktop\\java\\";
public void comile() throws Exception {
// javqComile 是java程序里的java编译器类
JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler();
// StandardJavaFileManager 对象主要负责
// 编译文件对象的创建,编译的参数等等,我们只对它做些基本设置比如编译 CLASSPATH 等。
StandardJavaFileManager standardJavaFileManager = javaCompiler.getStandardFileManager(null, null, null);
// JavaFileObject 为类文件上进行操作的工具的文件抽象
StringObject stringObject = new StringObject(className, javaSource2);
JavaFileObject javaFileObject = stringObject;
// Array Map Set 等都属于Itreable类型
Iterable options = Arrays.asList("-d", path);
Iterable<? extends JavaFileObject> files = Arrays.asList(javaFileObject);
// 通过一些选项,javafileObject, classPath 来获取JvaComiler.ComilationTask
JavaCompiler.CompilationTask task = javaCompiler.getTask(null,
standardJavaFileManager, null, options, null, files);
// 将Class 在内存中编译
Boolean result = task.call();
// 通过类名 加载class
ClassLoader classLoader = new ClassClassLoader(getClass().getClassLoader());
// ClassLoader classLoader = getClass().getClassLoader();
Class cls = classLoader.loadClass(className);
// java反射机制 method.setAcessible 设置允许访问
Method method = cls.getMethod(methoName, int.class);
method.setAccessible(true);
Object[] args = new Object[]{2};
args[0] = 1;
Object obj = method.invoke(null, args);
System.out.println(obj.toString());
}
public static void main(String[] args) {
try {
new TestComiles().comile();
} catch (Exception e) {
e.printStackTrace();
}
}
private class StringObject extends SimpleJavaFileObject {
private String contents = null;
public StringObject(String clasName, String contents) throws Exception {
super(URI.create("String:///" + clasName + Kind.SOURCE.extension), Kind.SOURCE);
this.contents = contents;
}
@Override
public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
return contents;
}
}
private class ClassClassLoader extends ClassLoader {
ClassClassLoader(ClassLoader parent) {
super(parent);
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
//这个classLoader的主要方法
String classPath = name.replace(".", "\\") + ".class";//将包转为目录
String classFile = path + classPath;//拼接完整的目录
Class clazz = null;
try {
byte[] data = getClassFileBytes(classFile);
clazz = defineClass(name, data, 0, data.length);
if (null == clazz) {//如果在这个类加载器中都不能找到这个类的话,就真的找不到了
}
} catch (Exception e) {
e.printStackTrace();
}
return clazz;
}
private byte[] getClassFileBytes(String classFile) throws Exception {
//采用NIO读取
FileInputStream fis = new FileInputStream(classFile);
FileChannel fileC = fis.getChannel();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
WritableByteChannel outC = Channels.newChannel(baos);
ByteBuffer buffer = ByteBuffer.allocateDirect(1024);
while (true) {
int i = fileC.read(buffer);
if (i == 0 || i == -1) {
break;
}
buffer.flip();
outC.write(buffer);
buffer.clear();
}
fis.close();
return baos.toByteArray();
}
}
}