这个是我转载的 希望你对你有帮助
Java动态编译 .
分类: java 2011-02-21 13:50 202人阅读 评论(0) 收藏 举报
简述
有这样的应用场景,我们提供一个基础应用系统平台,这个平台提供了一组面向用户的二次开发支持组件,包括在平台上扩展业务逻辑、修改规则引擎、编写业务组件等等。这就需要平台提供一套用于做二次开发的基础元数据规范,通过解析既定规范运行组建应用系统业务模块。技术平台将会提供二次开发组件的上下文运行时环境 ,以及组件生命周期的管理。
Java动态编译
动态编译需要注意的问题:
1、编译时输出路径问题,在相关集成开发环境下(Eclipse)测试环境与生产环境工作目录会不一样。
1.1、在eclipse下工作目录是项目目录。
1.2、生产环境下工作目录就要依情况而定了在没打成war包时会类是WEB-INF/classes
1.3、通过指定编译器参数(-d),标记编译字节码文件存储路径(见示例代码)。
2、要理解java、javac命令中的两个参数{classpath|sourcepath},加上verbose了解详细装载过程
2.1、classpath:搜索类路径(趋向与class文件),这块也可载入且编译相关java文件
2.2、sourcepath: 引用源文件路径,指定编译所关联的源文件(.java),在未打包情况下会直接将关联的源文件编译成.class[code]package org.ybygjy.basic.jvm;
import java.io.IOException;
import java.lang.reflect.Method;
import java.net.URI;
import java.util.Arrays;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import javax.tools.SimpleJavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import javax.tools.JavaCompiler.CompilationTask;
import javax.tools.JavaFileObject.Kind;
/**
* Java字节码的操纵之动态编译
* @author WangYanCheng
* @version 2011-2-17
*/
public class AutoCompiler {
/** 源代码 */
private String source;
/** 类名称 */
private String className;
/** 编译输出路径 */
private String outPath = ".";
/** 提取包名称 */
private Pattern packPattern = Pattern.compile("^package//s+([a-z0-9.]+);");
/** 提取类名称 */
private Pattern classNamePattern = Pattern.compile("class//s+([^{]+)");
/**
* Constructor
* @param source 源代码
* @param outPath 动态编译文件的输出路径
*/
public AutoCompiler(String source, String outPath) {
this.outPath = outPath;
this.setSource(source);
}
/**
* 编译
* @return 编译结果 true/false
* @throws Exception 抛出异常信息
*/
private boolean doCompile() throws Exception {
return new InnerCompiler(new URI(className), Kind.SOURCE, this.source).compile();
}
/**
* 调用
* @param methodName 方法名称
* @return result 调用结果
*/
public Object doInvoke(String methodName) {
ClassLoader classLoader = InnerCompiler.class.getClassLoader();
try {
Class classDef = classLoader.loadClass(className);
Method method = classDef.getMethod(methodName, new Class[] {});
Object result = method.invoke(null, new Object[] {});
return result;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 自动调用
* @param methodName 方法名称
* @return resultObj 调用结果
* @throws Exception 忽略所有异常(建议调整)
*/
public Object autoInvoke(String methodName) throws Exception {
Object result = null;
if (this.doCompile()) {
return doInvoke(methodName);
}
return result;
}
/**
* 设定参与编译的源代码
* @param source compiled source
*/
public void setSource(String source) {
String tmpName = analyseClassName(source);
this.className = tmpName.trim();
this.source = source;
}
/**
* 解析类名称
* @param source 源字符串
* @return className 类名称/空字符串
*/
private String analyseClassName(String source) {
String tmpName = "";
Matcher matcher = packPattern.matcher(source);
if (matcher.find()) {
tmpName = (matcher.group(1)).concat(".");
}
matcher = classNamePattern.matcher(source);
if (matcher.find()) {
tmpName = tmpName.concat(matcher.group(1));
}
return tmpName;
}
/**
* 指定类名称
* @param className 类名称
*/
public void setClassName(String className) {
this.className = className;
}
/**
* 设定输出路径
* @param outPath 输出路径
*/
public void setOutPath(String outPath) {
this.outPath = outPath;
}
/*
* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("AutoCompiler [className=");
builder.append(className);
builder.append(", source=");
builder.append(source);
builder.append("]");
return builder.toString();
}
/**
* 负责自动编译
* @author WangYanCheng
* @version 2011-2-17
*/
class InnerCompiler extends SimpleJavaFileObject {
/** content */
private String content;
/**
* Contructor
* @param uri uri
* @param kind kind
* @param content content
*/
public InnerCompiler(URI uri, Kind kind, String content) {
this(uri, kind);
this.content = content;
}
/**
* Constructor
* @param uri 编译源文件路径
* @param kind 文件类型
*/
protected InnerCompiler(URI uri, Kind kind) {
super(uri, kind);
}
/*
* (non-Javadoc)
* @see javax.tools.SimpleJavaFileObject#getCharContent(boolean)
*/
@Override
public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
return this.content;
}
/**
* 编译
* @return result 成功编译标记{true|false}
*/
public boolean compile() {
boolean result = false;
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);
Iterable<? extends JavaFileObject> fileObject = Arrays.asList(this);
Iterable options = Arrays.asList("-d", outPath);
CompilationTask task = compiler.getTask(null, fileManager, null, options, null, fileObject);
result = task.call();
return result;
}
}
/**
* 测试入口
* @param args 参数列表
* @throws Exception 抛出异常
*/
public static void main(String[] args) throws Exception {
String methodName = "compilerTest";
StringBuilder source = new StringBuilder(
"package org.ybygjy.basic.jvm; class TestCompiler {public static String compilerTest(){return /"HelloWorld/";}}");
AutoCompiler dctInst = new AutoCompiler(source.toString(), "./webRoot/WEB-INF/classes");
System.out.println(dctInst.autoInvoke(methodName));
// if (dctInst.doCompile()) {
// Object obj = dctInst.doInvoke(methodName);
// System.out.println(obj);
// }
}
}[/code] |