JDK 6动态编译—内存字符串编译方式
创始人
2024-07-25 16:30:21
0

 

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

    API对应的接口都在javax.tools包下面,常用编译方式有基于文本文件、内存字符串等,实际上基于URI的字节流都可以,也就是远程Java源代码也可以。对于常用的已有文件形式的动态编译网上的实例已经非常多,我在这里介绍下动态编译内存中以字符串的形式。

简单的代码流程如下:

Java代码
  1. //通过系统工具提供者获得动态编译器     
  2. JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();     
  3. //获得一个文件管理器,它的功能主要是提供所有文件操作的规则,     
  4. //如源代码路径、编译的classpath,class文件目标目录等,其相关属性都提供默认值     
  5. StandardJavaFileManager fileManager = compiler.getStandardFileManager(nullnullnull);     
  6.     
  7. //获得CompilationTask并调用     
  8. //获得CompilationTask方法原型:     
  9. getTask(Writer out,     
  10.      JavaFileManager fileManager,     
  11.      DiagnosticListenersuper JavaFileObject> diagnosticListener,     
  12.      Iterable options,     
  13.      Iterable classes,     
  14.      Iterableextends JavaFileObject> compilationUnits)     
  15.     
  16.     
  17. //简单调用例子     
  18. boolean b = jc.getTask(null, fileManager, nullnullnull, compilationUnits).call();  

    我这里介绍的字符串形式的编译(其它方式也会有相似的具体实现),还需要提供一个FileObject一个实现类,将相应的对象封装作为getTask()的最后一个参数来构建具体的编译Task.

JavaDoc提供的一个FileObject参考实现:

Class JavaSourceFromString

Java代码
  1. import java.net.URI;     
  2.     
  3. import javax.tools.SimpleJavaFileObject;     
  4.     
  5. public class JavaSourceFromString extends SimpleJavaFileObject {     
  6.     
  7.     /**    
  8.      *  源码    
  9.      */    
  10.     final String code;     
  11.     
  12.     /**    
  13.      * 构造方法:从字符串中构造一个FileObject    
  14.      * @param name the name of the compilation unit represented by this file object    
  15.      * @param code the source code for the compilation unit represented by this file object    
  16.      */    
  17.     JavaSourceFromString(String name, String code) {     
  18.         super(URI.create("string:///" + name.replace('.','/') + Kind.SOURCE.extension),     
  19.               Kind.SOURCE);     
  20.         this.code = code;     
  21.     }     
  22.     
  23.     @Override    
  24.     public CharSequence getCharContent(boolean ignoreEncodingErrors) {     
  25.         return code;     
  26.     }     
  27. }    



完整的测试类:
Class TestDyCompile

Java代码
  1. import java.io.File;     
  2. import java.io.IOException;     
  3. import java.util.Arrays;     
  4.     
  5. import javax.tools.JavaCompiler;     
  6. import javax.tools.JavaFileManager.Location;     
  7. import javax.tools.JavaFileObject;     
  8. import javax.tools.StandardJavaFileManager;     
  9. import javax.tools.StandardLocation;     
  10. import javax.tools.ToolProvider;     
  11.     
  12. import dyclass.Test;     
  13.     
  14.     
  15. public class TestDyCompile {     
  16.     
  17.     /**    
  18.      *     
  19.      * @author ZhangXiang    
  20.      * @param args    
  21.      * 2011-4-7    
  22.      */    
  23.     public static void main(String[] args) {     
  24.              
  25.         StringBuilder classStr = new StringBuilder("package dyclass;public class Foo implements Test{");     
  26.         classStr.append("public void test(){");     
  27.         classStr.append("System.out.println(\"Foo2\");}}");     
  28.              
  29.         JavaCompiler jc = ToolProvider.getSystemJavaCompiler();     
  30.         StandardJavaFileManager fileManager = jc.getStandardFileManager(nullnullnull);     
  31.         Location location = StandardLocation.CLASS_OUTPUT;     
  32.         File[] outputs = new File[]{new File("bin/")};     
  33.         try {     
  34.             fileManager.setLocation(location, Arrays.asList(outputs));     
  35.         } catch (IOException e) {     
  36.             e.printStackTrace();     
  37.         }     
  38.              
  39.         JavaFileObject jfo = new JavaSourceFromString("dyclass.Foo", classStr.toString());     
  40.         JavaFileObject[] jfos = new JavaFileObject[]{jfo};     
  41.         Iterableextends JavaFileObject> compilationUnits = Arrays.asList(jfos);     
  42.         boolean b = jc.getTask(null, fileManager, nullnullnull, compilationUnits).call();     
  43.         if(b){//如果编译成功     
  44.             try {     
  45.                 Test t = (Test) Class.forName("dyclass.Foo").newInstance();     
  46.                 t.test();     
  47.             } catch (InstantiationException e) {     
  48.                 e.printStackTrace();     
  49.             } catch (IllegalAccessException e) {     
  50.                 e.printStackTrace();     
  51.             } catch (ClassNotFoundException e) {     
  52.                 e.printStackTrace();     
  53.             }     
  54.         }     
  55.     }     
  56. }   



我在这里的具体业务类为dyclass.Foo,也就是我们需要动态编译的类,为了方便写业务的调用代码,也可以让我们的业务类实现一个接口,然后通过反射获得具体子类强制转换来调用。

Test接口:

Java代码
  1. public interface Test {     
  2.     //业务方法签名     
  3.     void test();     
  4. }   


另外,在代码中还有这么一段:

Java代码
  1.   Location location = StandardLocation.CLASS_OUTPUT;     
  2.          File[] outputs = new File[]{new File("bin/")};     
  3. try {     
  4.     fileManager.setLocation(location, Arrays.asList(outputs));     
  5. catch (IOException e) {     
  6.     e.printStackTrace();     
  7. }    

这段代码的作用相信大家一看到它就想到它的作用了,前面有说过JavaFileManager 的作用,我在这里设置了CLASS文件的输出目录,意图很简单,我的工程是在Eclipse运行的,项目的目标路径就是项目下的bin目录,如果不设置的话,class文件输出路径即为默认值,也就是直接在项目根路径下,后面直接调用就不能完成了。当然在其它一些应用场景中需要设置为自己需要的目录。
同样的方法可以设置JavaFileManager 其它的我们需要的文件规则属性(可以参照枚举类型StandardLocation),在这里就不一一介绍了。

 

 

相关内容

热门资讯

如何允许远程连接到MySQL数... [[277004]]【51CTO.com快译】默认情况下,MySQL服务器仅侦听来自localhos...
如何利用交换机和端口设置来管理... 在网络管理中,总是有些人让管理员头疼。下面我们就将介绍一下一个网管员利用交换机以及端口设置等来进行D...
施耐德电气数据中心整体解决方案... 近日,全球能效管理专家施耐德电气正式启动大型体验活动“能效中国行——2012卡车巡展”,作为该活动的...
20个非常棒的扁平设计免费资源 Apple设备的平面图标PSD免费平板UI 平板UI套件24平图标Freen平板UI套件PSD径向平...
Windows恶意软件20年“... 在Windows的早期年代,病毒游走于系统之间,偶尔删除文件(但被删除的文件几乎都是可恢复的),并弹...
德国电信门户网站可实时显示全球... 德国电信周三推出一个门户网站,直观地实时提供其安装在全球各地的传感器网络检测到的网络攻击状况。该网站...
为啥国人偏爱 Mybatis,... 关于 SQL 和 ORM 的争论,永远都不会终止,我也一直在思考这个问题。昨天又跟群里的小伙伴进行...
《非诚勿扰》红人闫凤娇被曝厕所... 【51CTO.com 综合消息360安全专家提醒说,“闫凤娇”、“非诚勿扰”已经被黑客盯上成为了“木...