【转】JDK 6动态编译类的一个例子
2012-03-13 12:29
393 查看
JDK6开始提供了动态编译的API,在许多应用场景都可以用得着,如动态加载(修改)服务、高性动态业务逻辑实现(用脚本或模板引擎实现效率满足不了需求)等都非常好用。
API对应的接口都在javax.tools包下面,常用编译方式有基于文本文件、内存字符串等,实际上基于URI的字节流都可以,也就是远程Java源代码也可以。
PS:这里作者给的例子是返回一个int型的结果,所以,可以直接用
来得到返回的结果。
如果,返回的结果集是一个对象,那么,就需要对返回的结果进行类型转换。
以List为例:
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; } }
相关文章推荐
- JDK动态代理的一个例子
- 一个简单的例子模拟JDK动态代理
- dojo小例子(20)动态加载的Select增加一个option空白项
- 【动态代理】【一个动态代理的例子】
- 一个动态sql的例子
- JDK与Cglib实现的动态代理区别以及例子说明
- JDK动态代理小例子
- (论坛答疑点滴)一个动态编译的例子
- 通过freemarker生成一个超简单的动态表单例子
- spring源码学习之【准备】jdk动态代理例子
- Java代理模式之JDK动态代理例子
- DataGrid动态添加模板列的一个例子
- 一个动态交叉报表的例子
- jdk动态代理的小例子
- 一个动态添加contextmenu的例子,以及其click事件
- 一个简单打开D盘所有文件夹和文件的例子以及动态创建双击事件
- DataGrid动态添加模板列的一个例子
- jdk动态代理小例子
- 实现动态代理的两种方式介绍+例子demo(JDK、CGlib)
- (原创)DataGrid动态添加模板列的一个例子