一、场景
平时我们学学用到在JVM运行时,动态编译.java的源代码情况,比如作为灵活的配置文件。这时候就要用到动态编译,参考下列。
二、类内容
1、引入依赖:
<!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
2、编写基本类,让它继承 SimpleJavaFileObject 类。
package com.songxingzhu.utils.compile; import javax.tools.SimpleJavaFileObject;
import java.net.URI; public class JavaSourceFromCodeString extends SimpleJavaFileObject {
final String code; public JavaSourceFromCodeString(String name, String code) {
super(URI.create("string:///" + name.replace('.', '/') + Kind.SOURCE.extension), Kind.SOURCE);
this.code = code;
} public CharSequence getCharContent(boolean ignoreEncodingErrors) {
return this.code;
}
}
2、编写工具类
package com.songxingzhu.utils.context; import java.io.File; public class AppContext {
public static String baseDirectory() {
try {
String path = ClassLoader.getSystemResource("").getPath();
if (path==null||"".equal(path))
return getProjectPath();
return path;
} catch (Exception ignored) {
}
return getProjectPath();
} private static String getProjectPath() {
java.net.URL url = AppContext.class.getProtectionDomain().getCodeSource()
.getLocation();
String filePath = null;
try {
filePath = java.net.URLDecoder.decode(url.getPath(), "UTF-8");
} catch (Exception e) {
e.printStackTrace();
}
if (filePath.endsWith(".jar"))
filePath = filePath.substring(0, filePath.lastIndexOf(File.separatorChar) + 1);
java.io.File file = new java.io.File(filePath);
filePath = file.getAbsolutePath();
return filePath;
}
}
package com.songxingzhu.utils.compile; import org.apache.commons.io.FileUtils;
import com.songxingzhu.utils.context.AppContext; import javax.tools.JavaCompiler;
import javax.tools.JavaFileManager;
import javax.tools.JavaFileObject;
import javax.tools.ToolProvider;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.List; public class ClassBuilder { public static Class<?> buildClass(String fullClassName, String codeFilePath) throws IOException, ClassNotFoundException { return buildClass(fullClassName, codeFilePath, "UTF-8", AppContext.baseDirectory());
} public static Class<?> buildClass(String fullClassName, String codeFilePath, String charsetName, String buildOutput) throws IOException, ClassNotFoundException {
try {
String code = FileUtils.readFileToString(FileUtils.getFile(codeFilePath), charsetName);
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
JavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);
List<JavaFileObject> files = new ArrayList<>();
files.add(new JavaSourceFromCodeString(fullClassName, code));
List<String> options = new ArrayList<>();
options.add("-classpath");
StringBuilder sb = new StringBuilder();
URLClassLoader urlClassLoader = (URLClassLoader) Thread.currentThread().getContextClassLoader();
for (URL url : urlClassLoader.getURLs()) {
sb.append(url.getFile()).append(File.pathSeparator);
}
options.add(sb.toString());
options.add("-d");
options.add(buildOutput);
// execute the compiler
boolean isok = compiler.getTask(null, fileManager, null, options, null, files).call();
if (isok) {
File root = new File(buildOutput);
if (!root.exists()) root.mkdirs();
URL[] urls = new URL[]{root.toURI().toURL()};
ClassLoader classLoader = ClassBuilder.class.getClassLoader();
Class<?> clazz = Class.forName(fullClassName, true, classLoader);
return clazz;
}
return null;
} catch (Exception ex) {
throw ex;
}
}
}