package com.ths.platform.framework.dynamic;
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.JavaFileObject;
import javax.tools.ToolProvider;
/**
* @author : jialin
* @group : THS_JAVA_PLATFORM
* @Date : 2014-10-25 上午10:43:42
* @Comments : 原理:
* 在Java SE6中最好的方法是使用StandardJavaFileManager类。
* 这个类可以很好地控制输入、输出,并且可以通过DiagnosticListener得到诊断信息,
* 而DiagnosticCollector类就是listener的实现。
* 使用StandardJavaFileManager需要两步。
* 首先建立一个DiagnosticCollector实例以及通过JavaCompiler的getStandardFileManager()方法得到一个StandardFileManager对象。
* 最后通过CompilationTask中的call方法编译源程序。
* @Version : 1.0.0
*/
public class DynamicEngine {
//单例
private static DynamicEngine ourInstance = new DynamicEngine();
public static DynamicEngine getInstance() {
return ourInstance;
}
private URLClassLoader parentClassLoader;
private String classpath;
private DynamicEngine() {
//获取类加载器
this.parentClassLoader = (URLClassLoader) this.getClass().getClassLoader();
//创建classpath
this.buildClassPath();
}
/**
* @MethodName : 创建classpath
* @Description : TODO
*/
private void buildClassPath() {
this.classpath = null;
StringBuilder sb = new StringBuilder();
for (URL url : this.parentClassLoader.getURLs()) {
String p = url.getFile();
sb.append(p).append(File.pathSeparator);
}
this.classpath = sb.toString();
}
/**
* @MethodName : 编译java代码到Object
* @Description : TODO
* @param fullClassName 类名
* @param javaCode 类代码
* @return Object
* @throws IllegalAccessException
* @throws InstantiationException
*/
public Object javaCodeToObject(String fullClassName, String javaCode) throws IllegalAccessException, InstantiationException {
long start = System.currentTimeMillis(); //记录开始编译时间
Object instance = null;
//获取系统编译器
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
// 建立DiagnosticCollector对象
DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>();
// 建立用于保存被编译文件名的对象
// 每个文件被保存在一个从JavaFileObject继承的类中
ClassFileManager fileManager = new ClassFileManager(compiler.getStandardFileManager(diagnostics, null, null));
List<JavaFileObject> jfiles = new ArrayList<JavaFileObject>();
jfiles.add(new CharSequenceJavaFileObject(fullClassName, javaCode));
//使用编译选项可以改变默认编译行为。编译选项是一个元素为String类型的Iterable集合
List<String> options = new ArrayList<String>();
options.add("-encoding");
options.add("UTF-8");
options.add("-classpath");
options.add(this.classpath);
JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager, diagnostics, options, null, jfiles);
// 编译源程序
boolean success = task.call();
if (success) {
//如果编译成功,用类加载器加载该类
JavaClassObject jco = fileManager.getJavaClassObject();
DynamicClassLoader dynamicClassLoader = new DynamicClassLoader(this.parentClassLoader);
Class clazz = dynamicClassLoader.loadClass(fullClassName,jco);
instance = clazz.newInstance();
} else {
//如果想得到具体的编译错误,可以对Diagnostics进行扫描
String error = "";
for (Diagnostic diagnostic : diagnostics.getDiagnostics()) {
error = error + compilePrint(diagnostic);
}
}
long end = System.currentTimeMillis();
System.out.println("javaCodeToObject use:"+(end-start)+"ms");
return instance;
}
/**
* @MethodName : compilePrint
* @Description : 输出编译错误信息
* @param diagnostic
* @return
*/
private String compilePrint(Diagnostic diagnostic) {
System.out.println("Code:" + diagnostic.getCode());
System.out.println("Kind:" + diagnostic.getKind());
System.out.println("Position:" + diagnostic.getPosition());
System.out.println("Start Position:" + diagnostic.getStartPosition());
System.out.println("End Position:" + diagnostic.getEndPosition());
System.out.println("Source:" + diagnostic.getSource());
System.out.println("Message:" + diagnostic.getMessage(null));
System.out.println("LineNumber:" + diagnostic.getLineNumber());
System.out.println("ColumnNumber:" + diagnostic.getColumnNumber());
StringBuffer res = new StringBuffer();
res.append("Code:[" + diagnostic.getCode() + "]\n");
res.append("Kind:[" + diagnostic.getKind() + "]\n");
res.append("Position:[" + diagnostic.getPosition() + "]\n");
res.append("Start Position:[" + diagnostic.getStartPosition() + "]\n");
res.append("End Position:[" + diagnostic.getEndPosition() + "]\n");
res.append("Source:[" + diagnostic.getSource() + "]\n");
res.append("Message:[" + diagnostic.getMessage(null) + "]\n");
res.append("LineNumber:[" + diagnostic.getLineNumber() + "]\n");
res.append("ColumnNumber:[" + diagnostic.getColumnNumber() + "]\n");
return res.toString();
}
}
内存中动态编译执行java代码



内存中动态编译执行Java代码是一种高级编程技巧,它允许我们在程序运行时根据需要创建、编译和执行新的Java代码。这种技术在某些场景下非常有用,比如在元编程、插件系统、自定义脚本执行或者代码热更新中。在Java中,我们可以使用Java的`javax.tools.JavaCompiler`接口及其相关的API来实现这个功能。 `javax.tools.JavaCompiler`是Java编译器工具接口,它是Java 6引入的一个新特性,提供了在运行时动态编译Java源码的能力。通过`ToolProvider`类,我们可以获取到`JavaCompiler`的实例。例如: ```java JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); ``` 接下来,我们需要创建一个`JavaFileManager`的实例,它是用于管理编译过程中涉及的文件对象的接口。我们通常会使用`StandardJavaFileManager`的子类`ForwardingJavaFileManager`,它可以让我们在内存中处理源代码而不是写入磁盘。 ```java StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null); ForwardingJavaFileManager<StandardJavaFileManager> forwardingFileManager = new ForwardingJavaFileManager<>(fileManager) { // 实现内存中的类加载逻辑 }; ``` 有了`JavaCompiler`和`JavaFileManager`后,我们可以定义一个`Iterable`的源代码对象,这通常是一个包含Java源代码的`String`。然后,我们可以调用`compiler.compile()`方法来编译这些源代码: ```java Iterable<? extends JavaFileObject> compilationUnits = ...; // 包含源代码的JavaFileObjects compiler.compile(compilationUnits, forwardingFileManager); ``` 在这个过程中,`ForwardingJavaFileManager`会捕获编译后的`.class`文件,并将其保留在内存中。我们可以通过重写`getClassLoader()`方法来实现自己的类加载逻辑,以便在运行时加载并执行这些动态编译的类。 一旦编译成功,我们就可以通过`ClassLoader`来加载并实例化这个动态编译的类,然后执行它的方法。由于整个过程都在内存中完成,因此不会在磁盘上留下任何临时文件,实现了“洁净无污染”。 内存中动态编译执行Java代码是一项强大的技术,它允许我们在程序运行时增加新的功能或调整现有行为。然而,这也带来了安全风险,因为恶意代码可能借此机会执行有害操作。因此,在实际应用中,必须谨慎处理动态编译的代码,确保其安全性和可靠性。
























- 1

- 粉丝: 3235
- 资源: 10
我的内容管理 展开
我的资源 快来上传第一个资源
我的收益
登录查看自己的收益我的积分 登录查看自己的积分
我的C币 登录后查看C币余额
我的收藏
我的下载
下载帮助


最新资源
- 物联网_Hyperf_号卡分销系统_商业管理平台_1741166037.zip
- 物联网_JavaScript_数据处理_实战指南_1741163780.zip
- mimikatz.zip
- 商城系统_JavaEE_基础实战_Education_1741165240.zip
- 物联网安全_环境与汇编语言资料集_1741162436.zip
- 物联网技术知识库_GetIoTtech_1741164152.zip
- 物流管理_智能快递柜_信息一体化_便捷存取系统_1741166166.zip
- 物联网智能家居开发教程_机智云平台_gokit套件_入门实践_1741162919.zip
- 互联网数据库_手势识别_手工艺产品_电商平台_1741166389.zip
- 智能水务管理平台_物联网系统_1741165672.zip
- dromara_dante-cloud_1741166044.zip
- 物联网_MQTT协议_数据监控_应用架构_1741162340.zip
- 物联网_Golang_轻量级开发平台_HummingBird_1741163726.zip
- 消息推送_CIM_即时通讯_应用框架_1741165443.zip
- 物联网_DC3_开源平台_解决方案_1741163145.zip
- AI人工智能教程&案例-2025.zip



- 1
- 2
- 3
- 4
- 5
前往页