您的位置:首页 > 编程语言 > Java开发

【转】JDK 6动态编译类的一个例子

2012-03-13 12:29 393 查看
JDK6开始提供了动态编译的API,在许多应用场景都可以用得着,如动态加载(修改)服务、高性动态业务逻辑实现(用脚本或模板引擎实现效率满足不了需求)等都非常好用。

API对应的接口都在javax.tools包下面,常用编译方式有基于文本文件、内存字符串等,实际上基于URI的字节流都可以,也就是远程Java源代码也可以。

package demo;

import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import javax.tools.SimpleJavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import java.io.IOException;
import java.lang.reflect.Method;
import java.net.URI;
import java.util.Arrays;

public class CompileString {
public static void main(String[] args) throws Exception {
//通过系统工具提供者获得动态编译器
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
//获得一个文件管理器,它的功能主要是提供所有文件操作的规则,
//如源代码路径、编译的classpath,class文件目标目录等,其相关属性都提供默认值
StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);

StringObject so = new StringObject("demo.CalculatorTest", "package demo;" +
"  class CalculatorTest {" +
"	public int multiply(int multiplicand, int multiplier) {" +
"		System.out.println(multiplicand);" +
"		System.out.println(multiplier);" +
"		return multiplicand * multiplier;" +
"	}" +
"}");

JavaFileObject file = so;

// 指定 javac 的命令行参数
// 注意:最好将编译后的.class文件放到当前JVM实例的类路径上,否则加载不了
Iterable<String> options = Arrays.asList("-d", "E:\\workspace\\demo\\bin");
// 指定有哪些源文件需要被编译
Iterable<? extends JavaFileObject> files = Arrays.asList(file);

JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager, null, options, null, files);

Boolean result = task.call();

if (result) {
System.out.println("编译成功");
Class<?> clazz = Class.forName("demo.CalculatorTest");

Object instance = clazz.newInstance();

Method m = clazz.getMethod("multiply", new Class[]{int.class, int.class});

Object[] o = new Object[]{1, 2};

Object returnObj =  m.invoke(instance, o);
System.out.println("方法返回的结果:" + returnObj.toString());
}
}
}

class StringObject extends SimpleJavaFileObject {
private String contents = null;

public StringObject(String className, String contents) throws Exception {
super(new URI(className), Kind.SOURCE);
this.contents = contents;
}

public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
return contents;
}
}


PS:这里作者给的例子是返回一个int型的结果,所以,可以直接用

Object returnObj =  m.invoke(instance, o);
System.out.println("方法返回的结果:" + returnObj.toString());


来得到返回的结果。

如果,返回的结果集是一个对象,那么,就需要对返回的结果进行类型转换。

以List为例:

package demo;

import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import javax.tools.SimpleJavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import java.io.IOException;
import java.lang.reflect.Method;
import java.net.URI;
import java.util.Arrays;
import java.util.List;

public class CompileString {
public static void main(String[] args) throws Exception {
//通过系统工具提供者获得动态编译器
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
//获得一个文件管理器,它的功能主要是提供所有文件操作的规则,
//如源代码路径、编译的classpath,class文件目标目录等,其相关属性都提供默认值
StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);

StringObject so = new StringObject("demo.CalculatorTest",
"package demo;"
+"import java.util.List;"
+"import java.util.ArrayList;"
+"class CalculatorTest {"
+"	public List<String> multiply(String str1, String str2) {"
+"		System.out.println(str1);"
+"		System.out.println(str2);"
+"		List<String> result = new ArrayList<String>();"
+"		result.add(str1);"
+"		result.add(str2);"
+"		return result;"
+"	}"
+"}");

JavaFileObject file = so;

// 指定 javac 的命令行参数
// 注意:最好将编译后的.class文件放到当前JVM实例的类路径上,否则加载不了
Iterable<String> options = Arrays.asList("-d", "E:\\workspace\\demo\\bin");
// 指定有哪些源文件需要被编译
Iterable<? extends JavaFileObject> files = Arrays.asList(file);

JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager, null, options, null, files);

Boolean result = task.call();

if (result) {
System.out.println("编译成功");
Class<?> clazz = Class.forName("demo.CalculatorTest");

Object instance = clazz.newInstance();

Method m = clazz.getMethod("multiply", new Class[]{String.class, String.class});

Object[] o = new Object[]{"1", "2"};

List returnObj =  (List) m.invoke(instance, o);

System.out.println("方法返回的结果集个数:" + returnObj.size());
}
}
}

class StringObject extends SimpleJavaFileObject {
private String contents = null;

public StringObject(String className, String contents) throws Exception {
super(new URI(className), Kind.SOURCE);
this.contents = contents;
}

public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
return contents;
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: