@RequestMapping("/test/load")
@ResponseBody
public AjaxResult classLoad(@NotBlank String key) throws Exception {
// String javaSrc = exampleService.findConfigByKey(key);//从数据库获取以下源码
String javaSrc = " import com.eos.wxapp.controller.test.Singer;\n" +
"public class ZBC implements Singer {\n" +
" @Override\n" +
" public void sing() {\n" +
" System.out.println(\"一首凉凉送给你\");\n" +
" }\n" +
"}\n";
String className = "ZBC";
try {
Test.testInvoke(className, javaSrc);
} catch (ClassNotFoundException | IllegalAccessException
| InstantiationException | NoSuchMethodException
| InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return AjaxResult.success();
}
public static void testInvoke(String className, String source) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
final String SUFFIX = ".java";// 类名后面要跟的后缀
// 对source进行编译生成class文件存放在Map中,这里用bytecode接收
Map<String, byte[]> bytecode = DynamicLoader.compile(className + SUFFIX,
source);
// 加载class文件到虚拟机中,然后通过反射执行
@SuppressWarnings("resource")
DynamicLoader.MemoryClassLoader classLoader = new DynamicLoader.MemoryClassLoader(
bytecode);
Class<?> clazz = classLoader.loadClass("ZBC");
Singer someone = (Singer) clazz.newInstance();
someone.sing();
}
import java.io.IOException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
public class DynamicLoader {
/**
* 通过类名和其代码(Java代码字符串),编译得到字节码,,封装于Map中,值得注意的是,
* 平常类中就编译出来的字节码只有一个类,但是考虑到内部类的情况, 会出现返回类名及其对应类的字节码很多个类名及其字节码,所以用Map封装方便。
*
* @param javaName 类名
* @param javaSrc Java源码
* @return map
*/
public static Map<String, byte[]> compile(String javaName, String javaSrc) {
// 调用java编译器接口
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager stdManager = compiler
.getStandardFileManager(null, null, null);
try (MemoryJavaFileManager manager = new MemoryJavaFileManager(
stdManager)) {
@SuppressWarnings("static-access")
JavaFileObject javaFileObject = manager.makeStringSource(javaName,
javaSrc);
JavaCompiler.CompilationTask task = compiler.getTask(null, manager,
null, null, null, Arrays.asList(javaFileObject));
if (task.call()) {
return manager.getClassBytes();
}
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
/**
* 先根据类名在内存中查找是否已存在该类,若不存在则调用 URLClassLoader的 defineClass方法加载该类
* URLClassLoader的具体作用就是将class文件加载到jvm虚拟机中去
*
* @author Administrator
*
*/
public static class MemoryClassLoader extends URLClassLoader {
Map<String, byte[]> classBytes = new HashMap<String, byte[]>();
public MemoryClassLoader(Map<String, byte[]> classBytes) {
super(new URL[0], MemoryClassLoader.class.getClassLoader());
this.classBytes.putAll(classBytes);
}
@Override
protected Class<?> findClass(String name)
throws ClassNotFoundException {
byte[] buf = classBytes.get(name);
if (buf == null) {
return super.findClass(name);
}
classBytes.remove(name);
return defineClass(name, buf, 0, buf.length);
}
}
}
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.Reader;
import java.io.StringReader;
import java.net.URI;
import java.nio.CharBuffer;
import java.util.HashMap;
import java.util.Map;
import javax.tools.FileObject;
import javax.tools.ForwardingJavaFileManager;
import javax.tools.JavaFileManager;
import javax.tools.JavaFileObject;
import javax.tools.SimpleJavaFileObject;
/**
* 将编译好的.class文件保存到内存当中,这里的内存也就是map映射当中
*/
@SuppressWarnings("rawtypes")
public final class MemoryJavaFileManager extends ForwardingJavaFileManager {
private final static String EXT = ".java";// Java源文件的扩展名
private Map<String, byte[]> classBytes;// 用于存放.class文件的内存
@SuppressWarnings("unchecked")
public MemoryJavaFileManager(JavaFileManager fileManager) {
super(fileManager);
classBytes = new HashMap<String, byte[]>();
}
public Map<String, byte[]> getClassBytes() {
return classBytes;
}
@Override
public void close() throws IOException {
classBytes = new HashMap<String, byte[]>();
}
@Override
public void flush() throws IOException {
}
/**
* 一个文件对象,用来表示从string中获取到的source,一下类容是按照jkd给出的例子写的
*/
private static class StringInputBuffer extends SimpleJavaFileObject {
// The source code of this "file".
final String code;
/**
* Constructs a new JavaSourceFromString.
*
* @param name 此文件对象表示的编译单元的name
* @param code 此文件对象表示的编译单元source的code
*/
StringInputBuffer(String name, String code) {
super(toURI(name), Kind.SOURCE);
this.code = code;
}
@Override
public CharBuffer getCharContent(boolean ignoreEncodingErrors) {
return CharBuffer.wrap(code);
}
@SuppressWarnings("unused")
public Reader openReader() {
return new StringReader(code);
}
}
/**
* 将Java字节码存储到classBytes映射中的文件对象
*/
private class ClassOutputBuffer extends SimpleJavaFileObject {
private String name;
/**
* @param name className
*/
ClassOutputBuffer(String name) {
super(toURI(name), Kind.CLASS);
this.name = name;
}
@Override
public OutputStream openOutputStream() {
return new FilterOutputStream(new ByteArrayOutputStream()) {
@Override
public void close() throws IOException {
out.close();
ByteArrayOutputStream bos = (ByteArrayOutputStream) out;
// 这里需要修改
classBytes.put(name, bos.toByteArray());
}
};
}
}
@Override
public JavaFileObject getJavaFileForOutput(
JavaFileManager.Location location, String className,
JavaFileObject.Kind kind, FileObject sibling) throws IOException {
if (kind == JavaFileObject.Kind.CLASS) {
return new ClassOutputBuffer(className);
} else {
return super.getJavaFileForOutput(location, className, kind,
sibling);
}
}
public static JavaFileObject makeStringSource(String name, String code) {
return new StringInputBuffer(name, code);
}
static URI toURI(String name) {
File file = new File(name);
if (file.exists()) {// 如果文件存在,返回他的URI
return file.toURI();
} else {
try {
final StringBuilder newUri = new StringBuilder();
newUri.append("mfm:///");
newUri.append(name.replace('.', '/'));
if (name.endsWith(EXT)) {
newUri.replace(newUri.length() - EXT.length(),
newUri.length(), EXT);
}
return URI.create(newUri.toString());
} catch (Exception exp) {
return URI.create("mfm:///com/sun/script/java/java_source");
}
}
}
}
package com.xx.xx.controller.test;
/**
* @author Maple
* @Description:
* @date 2021/1/2510:42
*/
public interface Singer {
public void sing();
}
版权声明:本文为maple980326原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。