- import java.io.File;
- import java.net.URL;
- import java.net.URLClassLoader;
- import java.util.ArrayList;
- import java.util.List;
- import javax.tools.Diagnostic;
- import javax.tools.DiagnosticCollector;
- import javax.tools.JavaCompiler;
- import javax.tools.ToolProvider;
- import org.apache.log4j.Logger;
- /**
- * 动态重新加载Class <br>
- * Java内置的ClassLoader总会在加载一个Class之前检查这个Class是否已经被加载过 <br>
- * 已经被加载过的Class不会加载第二次 <br>
- * 因此要想重新加载Class,我们需要实现自己的ClassLoader <br>
- * 另外一个问题是,每个被加载的Class都需要被链接(link), <br>
- * 这是通过执行ClassLoader.resolve()来实现的,这个方法是 final的,无法重写。 <br>
- * ClassLoader.resolve()方法不允许一个ClassLoader实例link一个Class两次, <br>
- * 因此,当需要重新加载一个 Class的时候,需要重新New一个自己的ClassLoader实例。 <br>
- * 一个Class不能被一个ClassLoader实例加载两次,但是可以被不同的ClassLoader实例加载, <br>
- * 这会带来新的问题 <br>
- * 在一个Java应用中,Class是根据它的全名(包名+类名)和加载它的 ClassLoader来唯一标识的, <br>
- * 不同的ClassLoader载入的相同的类是不能互相转换的。 <br>
- * 解决的办法是使用接口或者父类,只重新加载实现类或者子类即可。 <br>
- * 在自己实现的ClassLoader中,当需要加载接口或者父类的时候,要代理给父ClassLoader去加载 <br>
- *
- * @author ...
- * @version 2012-11
- * @since jdk1.6.0
- */
- public class DynamicEngine {
- private static Logger logger = Logger.getLogger(DynamicEngine.class);
- private static DynamicEngine instance = new DynamicEngine();
- private URLClassLoader parentClassLoader;
- private String classpath;
- public static DynamicEngine getInstance() {
- return instance;
- }
- private DynamicEngine() {
- this.parentClassLoader = (URLClassLoader) getClass().getClassLoader();
- buildClassPath();
- }
- private void buildClassPath() {
- StringBuilder sb = new StringBuilder();
- for (URL url : this.parentClassLoader.getURLs()) {
- String p = url.getFile();
- sb.append(p);
- sb.append(File.pathSeparator);
- }
- this.classpath = sb.toString();
- }
- /**
- * 编译Java代码(用来检查代码正确性)
- *
- * @param className
- * @param javaCode
- * @return 编译通过则为null,不通过返回错误日志
- */
- @SuppressWarnings({ "rawtypes", "unchecked" })
- public String javaCodeCompile(String className, String javaCode) {
- long start = System.currentTimeMillis();
- JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
- DiagnosticCollector diagListener = new DiagnosticCollector();
- ObjectFileManager fileManager = new ObjectFileManager(compiler.getStandardFileManager(diagListener, null, null));
- List<StringFileObject> compileUnits = new ArrayList<StringFileObject>(1);
- compileUnits.add(new StringFileObject(className, javaCode));
- List<String> options = new ArrayList<String>(4);
- options.add("-encoding");
- options.add("UTF-8");
- options.add("-classpath");
- options.add(this.classpath);
- JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager, diagListener, options, null, compileUnits);
- boolean success = task.call().booleanValue();
- if (success) {
- long end = System.currentTimeMillis();
- logger.info("编译成功,用时:" + (end - start) + "ms");
- } else {
- StringBuilder error = new StringBuilder();
- for (Object diagnostic : diagListener.getDiagnostics()) {
- compilePrint(javaCode, error, (Diagnostic) diagnostic);
- }
- logger.error("编译失败:\n" + error);
- return error.toString();
- }
- return null;
- }
Java动态编译笔记
最新推荐文章于 2024-09-06 14:19:19 发布