一、场景
平时我们学学用到在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; } } }