动态编译(DynamicCompile)

一、动态编译

在程序运行期间,能够动态完成源文件到字节码文件的编译。

二、目标源文件Target.java

package com.mo;

/**
 * 这是一个源码文件,放在resources目录下,则是一个静态的文件
 *
 * @author x.pan
 * @email px5215201314@163.com
 * @date 2020/7/13 21:59
 */
public class Target {

    /**
     * 简单的一个方法
     * 测试动态编译
     *
     * @return
     */
    public String run() {
        System.out.println("运行成功 ...");
        return "success;";
    }
}

三、Runtime

    /**
     * 调用Runtime进程使用javac实现动态编译
     */
    @Test
    public void runtime() throws Exception{
        // 获取项目编译后的根据路径
        URL classes = this.getClass().getResource("/");
        // 获取预先定义的java文件
        URL targetFile = ClassLoader.getSystemResource("Target.java");

        //  1. 返回一个java相关的运行对象进程
        Runtime runtime = Runtime.getRuntime();
        /**
         * 2. 执行javac编译命令
         *  -encoding 指定编码
         *  -cp 指定classpath,jar包中间使用;分隔
         *  -d 类文件的目标文件夹
         */
        Process process = runtime.exec("javac -encoding UTF-8 -cp . " + targetFile.getPath() + " -d " + classes.getPath());
        // 3. 当前线程等待,知道Process进程执行完
        process.waitFor();
        // 4. 获取进程执行结果,0 表示正常终止
        if (process.exitValue() == 0) {


            /**
             * 加载编译后的class,并且运行
             */
            ClassLoader classLoader = ClassLoader.getSystemClassLoader();
            Class<?> aClass = classLoader.loadClass("com.mo.Target");
            Method run = aClass.getDeclaredMethod("run");
            Object o = aClass.newInstance();
            run.invoke(o);
        } else {
            System.out.println("非正常终止");
        }
    }

 

四、JavaCompiler

    /**
     * 方式一
     * 
     * 使用JavaCompiler进行编译
     * <p>
     * 注意:如果报java.lang.ClassNotFoundException: com.sun.tools.javac.processing.JavacProcessingEnvironment
     * 原因是com.sun.tools无法加载
     */
    @Test
    public void tool() throws Exception {
        // 获取项目编译后的根据路径
        URL classes = this.getClass().getResource("/");
        // 获取预先定义的java文件
        URL targetFile = ClassLoader.getSystemResource("Target.java");

        // 1. 获取系统的java编译器
        JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler();
        // 2. 使用编译器编译文件
        int exitValue = javaCompiler.run(null, null, null, "-encoding", "UTF-8", "-cp", ".", targetFile.getPath(), "-d", classes.getPath());
        // 3. 获取返回结果
        if (exitValue == 0) {
            /**
             * 加载编译后的class,并且运行
             */
            ClassLoader classLoader = ClassLoader.getSystemClassLoader();
            Class<?> aClass = classLoader.loadClass("com.mo.Target");
            Method run = aClass.getDeclaredMethod("run");
            Object o = aClass.newInstance();
            run.invoke(o);
        } else {
            System.out.println("非正常终止");
        }
    }

 

    /**
     * 方式二
     * 使用JavaCompiler文件系统进行编译
     *
     * @throws Exception
     */
    @Test
    public void tools() throws Exception {
        // 获取项目编译后的根据路径
        URL classes = this.getClass().getResource("/");
        // 获取预先定义的java文件
        URL targetFile = ClassLoader.getSystemResource("Target.java");
        File file = new File(targetFile.toURI());
        // 1. 获取JavaCompiler
        JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler();
        /**
         * 2. 获取文件系统
         *  diagnosticListener - 用于非致命诊断信息的诊断侦听器;如果为 null,则使用编译器的默认方法来报告诊断信息
         *  locale - 格式化诊断信息时要应用的语言环境;如果为 null,则使用默认语言环境。
         *  charset - 用于解码字节的字符集;如果为 null,则使用平台默认的字符集
         */
        StandardJavaFileManager fileManager = javaCompiler.getStandardFileManager(null, null, null);
        // 3. 文件管理器根与文件连接起来
        Iterable<? extends JavaFileObject> compilationUnits = fileManager.getJavaFileObjects(file);
        /**
         * 4. 创建编译的任务
         *  out - 用于来自编译器的其他输出的 Writer;如果为 null,则使用 System.err
         *  fileManager - 文件管理器;如果为 null,则使用编译器的标准文件管理器
         *  diagnosticListener - 诊断侦听器;如果为 null,则使用编译器的默认方法报告诊断信息
         *  options - 编译器选项;null 表示没有选项
         *  classes - 类名称(用于注释处理),null 表示没有类名称
         *  compilationUnits - 要编译的编译单元;null 表示没有编译单元
         */
        JavaCompiler.CompilationTask task = javaCompiler.getTask(null, fileManager, null, Arrays.asList("-d", classes.getPath()), null, compilationUnits);
        // 5. 执行编译
        task.call();
        fileManager.close();

        /**
         * 加载编译后的class,并且运行
         */
        ClassLoader classLoader = ClassLoader.getSystemClassLoader();
        Class<?> aClass = classLoader.loadClass("com.mo.Target");
        Method run = aClass.getDeclaredMethod("run");
        Object o = aClass.newInstance();
        run.invoke(o);
    }

 

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值