• Java_Java SE6调用动态编译


    转自:http://www.cnblogs.com/flyoung2008/archive/2011/11/14/2249017.html

    一、使用JavaCompiler接口编译java源程序

      我们可以通过ToolProvider类的静态方法getSystemJavaCompiler来得到一个JavaCompiler接口的实例。

     JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();

      JavaCompiler中最核心的方法是run。通过这个方法可以编译java源程序。这个方法有3个固定参数和1个可变参数(可变参数是从Jave SE5开始提供的一个新的参数类型,用type… argu表示)。前3个参数分别用来为java编译器提供参数、得到Java编译器的输出信息以及接收编译器的错误信息,后面的可变参数可以传入一个或多 个Java源程序文件。如果run编译成功,返回0。

     int run(InputStream in, OutputStream out, OutputStream err, String... arguments) 

      如果前3个参数传入的是null,那么run方法将以标准的输入、输出代替,即System.in、System.out和System.err。

      下面是利用java动态编译实现eval功能:

    复制代码
    package com.flyoung;

    import java.io.File;
    import java.io.FileWriter;
    import java.io.PrintWriter;
    import java.lang.reflect.Method;

    import javax.tools.JavaCompiler;
    import javax.tools.ToolProvider;

    public class JavacTest {
    public JavacTest(){

    }

    public static void eval(String str){
    System.out.println(System.getProperty("user.dir"));//当前工作目录
    String s = "public class Temp{" ;
    s+=" "+" public static String call(String ss){ ";
    s+=" "+" System.out.println(""+str+""); ";
    s+=" "+" return "return_str"; ";
    s+=" "+" }";
    s+=" "+"}";
    try{
    File file = new File("Temp.java");
    PrintWriter pw = new PrintWriter(new FileWriter(file));
    //pw.println(s);
    //pw.write(s);
    pw.close();

    //动态编译
    JavaCompiler javac = ToolProvider.getSystemJavaCompiler();
    int status = javac.run(null, null, null, "-d",System.getProperty("user.dir")+"/bin","Temp.java");
    if(status!=0){
    System.out.println("没有编译成功!");
    }

    //动态执行
    Class cls = Class.forName("Temp");//返回与带有给定字符串名的类 或接口相关联的 Class 对象。
    Method method = cls.getDeclaredMethod("call", String.class);//返回一个 Method 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明方法
    String result= (String)method.invoke(null, str);//静态方法第一个参数可为null,第二个参数为实际传参
    System.out.println(result);
    }catch(Exception e){
    e.printStackTrace();
    }

    }
    /**
    * @param args
    */
    public static void main(String[] args) {
    // TODO Auto-generated method stub
    JavacTest javacTest = new JavacTest();
    javacTest.eval("input_str");

    }

    }
    复制代码

    二、使用StandardJavaFileManager编译java源程序

      在Java SE6中最好的方法是使用StandardJavaFileManager类。这个类可以很好地控制输入、输出,并且可以通过DiagnosticListener得到诊断信息,而DiagnosticCollector类就是listener的实现。
      使用StandardJavaFileManager需要两步。首先建立一个DiagnosticCollector实例以及通过 JavaCompiler的getStandardFileManager()方法得到一个StandardFileManager对象。最后通过 CompilationTask中的call方法编译源程序。

    详细请看:http://doc.java.sun.com/DocWeb/api/javax.tools.JavaCompiler

    示例:

    复制代码
    package com.flyoung;
    import java.io.File;
    import java.io.FileWriter;
    import java.util.Arrays;
    import javax.tools.JavaCompiler;
    import javax.tools.StandardJavaFileManager;
    import javax.tools.ToolProvider;
    import javax.tools.JavaCompiler.CompilationTask;
    public class DynamicCompileTest {
    public static void main(String[] args) throws Exception {
    //1.创建需要动态编译的代码字符串
    String nr=" ";//回车换行
    String source="package com.flyoung.hello;"+nr+
    " public class Hello{"+nr+
    " public static void main(String[] args){"+nr+
    " System.out.println("helloworld!");"+nr+
    "}"+nr+
    "}" ;
    //2.将预动态编译的代码写入文件中1:创建临时目录 2:写入临时文件
    File dir=new File(System.getProperty("user.dir")+"/temp");//临时目录
    //如果/temp目录不存在创建temp目录
    if(!dir.exists()){
    dir.mkdir();
    }
    FileWriter writer=new FileWriter(new File(dir,"Hello.java"));
    writer.write(source);//将字符串写入文件中
    writer.flush();
    writer.close();
    //3:取得当前系统java编译器
    JavaCompiler javaCompiler=ToolProvider.getSystemJavaCompiler();
    //4:获取一个文件管理器StandardJavaFileManage
    StandardJavaFileManager javaFileManager=javaCompiler.getStandardFileManager(null, null, null);
    //5.文件管理器根与文件连接起来
    Iterable it=javaFileManager.getJavaFileObjects(new File(dir,"Hello.java"));
    //6.创建编译的任务
    CompilationTask task=javaCompiler.getTask(null,
    javaFileManager,null,Arrays.asList("-d","./temp"), null, it);
    //执行编译
    task.call();
    javaFileManager.close();
    }
    }
    复制代码

    三、从内存中动态编译源程序

          JavaCompiler 不仅能编译硬盘上的 Java 文件,而且还能编译内存中的 Java 代码,然后使用reflection来运行他们。

    复制代码
    package com.flyoung;
    import java.io.IOException;
    import java.net.URI;
    import javax.tools.SimpleJavaFileObject;
    public class JavaStringObject extends SimpleJavaFileObject {
    private String code;
    public JavaStringObject(String name, String code) {
    //super(URI.create("string:///" + name.replace('.', '/') + Kind.SOURCE.extension), Kind.SOURCE);
    super(URI.create(name+".java"), Kind.SOURCE);
    this.code = code;
    }
    @Override
    public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException
    {
    return code;
    }
    }
    复制代码
    复制代码
    package com.flyoung;

    import java.io.PrintWriter;
    import java.io.StringWriter;
    import java.lang.reflect.Method;
    import java.net.URL;
    import java.net.URLClassLoader;
    import java.util.Arrays;
    import javax.tools.JavaCompiler;
    import javax.tools.JavaFileObject;
    import javax.tools.ToolProvider;
    import javax.tools.JavaCompiler.CompilationTask;
    public class DynamicCompileTest {
    public static void main(String[] args) throws Exception {
    /*
    * 编译内存中的java代码
    */
    // 将代码写入内存中
    StringWriter writer = new StringWriter();// 内存字符串输出流
    PrintWriter out = new PrintWriter(writer);
    out.println("package com.flyoung.hello;");
    out.println("public class Hello{");
    out.println("public static void main(String[] args){");
    out.println("System.out.println("helloworld!");");
    out.println("}");
    out.println("}");
    out.flush();
    out.close();
    // 开始编译
    JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler();
    JavaFileObject fileObject = new JavaStringObject("Hello", writer.toString());
    CompilationTask task=javaCompiler.getTask(null, null, null,
    Arrays.asList("-d","./bin"), null, Arrays.asList(fileObject));
    boolean success=task.call();
    if(!success){
    System.out.println("编译失败!");
    }
    else{
    System.out.println("编译成功!");
    //利用反射调用其中的main()方法
    // Class class1=Class.forName("com.flyoung.hello.Hello");
    //ClassLoader是自动去从当前工作目录下的classpath路径下去找 也就是bin目录下
    //Class class1=ClassLoader.getSystemClassLoader().loadClass("com.flyoung.hello.Hello");

    //利用URLClassLoader去实例化一个Class类 类文件可以放在任意位置,这样就很方便了
    URL[] urls=new URL[]{new URL("file:/"+"./bin/")};
    URLClassLoader classLoader=new URLClassLoader(urls);
    Class class1=classLoader.loadClass("com.flyoung.hello.Hello");
    Method method=class1.getDeclaredMethod("main",String[].class);
    String[] args1={null};
    method.invoke(class1.newInstance(),args1);
    }
    }
    }
    复制代码
  • 相关阅读:
    【记录】JS正则表达式(学习笔记2)现学现卖还帮美女解决了个问题。
    【分享】封装获取dom元素那些讨厌的位置
    【记录】简单去除数组重复项
    【记录】JS 预加载图片
    【分享】详解js函数调用的4中方法!
    【记录】JavaScript版 快速排序,还请高手指教。
    【分享】封装window.showModalDialog让他更好用(弹出窗口)
    【记录】正则表达式学习第3天(正则学习笔记),又解决了个实际问题。
    【分享】LazyLoad延迟加载(按需加载)
    PPT幻灯片放映不显示备注,只让备注显示在自己屏幕上
  • 原文地址:https://www.cnblogs.com/gisblogs/p/5504105.html
Copyright © 2020-2023  润新知