• java 动态编译运行


    写在前面

    Java Compiler 可以动态执行一段字符串形式的java代码,或手动编译java文件。

    1、Java Compiler

    1.1、java文件编译成class文件

    run 编译

    D:\Test.java 文件内容:

    public class Test {
        public static void main(String[] args) {
    		int i = 0;
            System.out.println("test run "+i);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    把java文件编译成class文件

            JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
            int result = compiler.run(null, null, null, "D:\\Test.java");   // 在 D:\\Test.java 同目录下,会出现Test.class文件
            System.out.println(result == 0 ? "编译成功" : "编译失败");
    
    • 1
    • 2
    • 3
    exec 执行指令

    exec 执行指令,等同于在cmd中输入指令

            // 执行java命令,空参数,所在文件夹
            Process process = Runtime.getRuntime().exec("java Test", null, new File("F:\\demo\\"));
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
            String str;
            while ((str = bufferedReader.readLine()) != null) {
                System.out.println(str);    // 这里打印的是控制台输出的
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    如上代码,等同于在cmd输入:java Test

    在这里插入图片描述

    1.2、字符串编译成class文件

    新建类 StringObject,代表字符串java对象内容

    package com.kaka;
    
    import javax.tools.SimpleJavaFileObject;
    import java.io.IOException;
    import java.net.URI;
    import java.net.URISyntaxException;
    
    // 必须继承自SimpleJavaFileObject 
    public class StringObject extends SimpleJavaFileObject {
        private String content = null;
    
        protected StringObject(String className, String contents) throws URISyntaxException {
            super(new URI(className), Kind.SOURCE);
            this.content = contents;
        }
    
        @Override
        public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
            return content;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    编译java字符串

    package com.kaka;
    
    import javax.tools.*;
    import java.net.URISyntaxException;
    import java.util.Collections;
    
    public class Test01 {
    
        public static void main(String[] args) throws URISyntaxException {
            // 要编译的字符串,这个字符串必须是一个类
            String contents = "package com.kaka;" +
                    "class Test {\n" +
                    "    public static void main(String[] args) {\n" +
                    "\tint i = 0;\n" +
                    "        System.out.println(\"测试运行 \"+i);\n" +
                    "    }\n" +
                    "}";
    
            JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler();
            StandardJavaFileManager standardJavaFileManager = javaCompiler.getStandardFileManager(null, null, null);
            JavaFileObject testFile = new StringObject("com.kaka.Test", contents);
            JavaCompiler.CompilationTask task = javaCompiler.getTask(null, standardJavaFileManager, null, null, null, Collections.singletonList(testFile));
            if(task.call()){
                System.out.println("success");
            }else{
                System.out.println("failure!");
            }
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    1.3、工具类

    将1.1和1.2总结为一个工具类

    package com;
    
    import javax.tools.*;
    import java.io.BufferedReader;
    import java.io.File;
    import java.io.FileReader;
    import java.io.IOException;
    import java.lang.reflect.Method;
    import java.net.URI;
    import java.util.Arrays;
    import java.util.Collections;
    import java.util.List;
    
    public class JavaCodeUtil {
        /** java字符串代码,转为class文件 **/
        public static String codeToClass(String code,String compilePath) {
            String className = getClassNameFromCode(code);
            JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler();
            StandardJavaFileManager fileManager = javaCompiler.getStandardFileManager(null, null, null);
            JavaFileObject stringObject = new StringObject(className, code);
            // compilePath 指定编译的class文件的路径
            List<String> options = Arrays.asList("-d", compilePath);
            JavaCompiler.CompilationTask task = javaCompiler.getTask(null, fileManager, null, options, null, Collections.singletonList(stringObject));
            if(task.call()){
                // 从code第一行读出包名
                String packageName = getPackageNameInFirstLine(code);
                String classFileName = className + "." + "class";
                return compilePath + "/" +  packageName + "/" + classFileName;
            }else{
                return null;
            }
        }
    
        public static String javaToClass(String fileName,String compilePath) throws IOException {
            JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler();
            StandardJavaFileManager fileManager = javaCompiler.getStandardFileManager(null, null, null);
            Iterable<? extends JavaFileObject> fileObjects = fileManager.getJavaFileObjects(fileName);
            // compilePath 指定编译的class文件的路径
            List<String> options = Arrays.asList("-d", compilePath);
            JavaCompiler.CompilationTask task = javaCompiler.getTask(null, fileManager, null, options, null, fileObjects);
            if(task.call()){
                // 从文件第一行读包名
                File sourceFile = new File(fileName);
                BufferedReader bufferedReader = new BufferedReader(new FileReader(sourceFile));
                String line;
                while ((line = bufferedReader.readLine()) != null) {
                    if (line.startsWith("package")) {
                        break;
                    }
                }
                String packageName = line;
                packageName = packageName.replaceAll("package", "").trim().replaceAll("\\.", "/");
                packageName = packageName.substring(0, packageName.length() - 1);
    
                // 获取类名(这里简单处理, 默认文件名与类名相同)
                String sourceFileName = sourceFile.getName();
    
                String[] split = sourceFileName.split("\\.");
                String simpleClassName = split[0] + "." + "class";
    
                return compilePath + "/" +  packageName + "/" + simpleClassName;
            }else{
                return null;
            }
        }
    
        public static class StringObject extends SimpleJavaFileObject {
            private final String content;
            public StringObject(String className, String contents) {
                super(URI.create(className), Kind.SOURCE);
                this.content = contents;
            }
            @Override
            public CharSequence getCharContent(boolean ignoreEncodingErrors){
                return content;
            }
        }
    
        /** 根据java文件第一行获取包名 */
        public static String getPackageNameInFirstLine(String code){
            return code
                    .substring(0,code.indexOf(";"))
                    .replace("package ", "")
                    .replaceAll("\\.", "/");
        }
    
        /** 从java String字符串中获取类名 */
        public static String getClassNameFromCode(String code){
            int classBlank = code.indexOf("class ")+6;
            String className = code.substring(classBlank);
            int nextBlank = className.indexOf(" ");
            className = className.substring(0,nextBlank);
            if(className.contains("{")){
                int i = className.indexOf("{");
                className = className.substring(0,i);
            }
            return className;
        }
    
        /** 获取项目根目录 */
        public static String getProjectPath() {
            String path = JavaCodeUtil.class.getProtectionDomain().getCodeSource().getLocation().getPath();
            if (System.getProperty("os.name").contains("dows")) {
                path = path.substring(1);
            }
    
            if (path.contains("jar")) {
                path = path.substring(0, path.lastIndexOf("."))
                        .substring(0, path.lastIndexOf("/"));
                return path;
            } else {
                return path.replace("target/classes/", "");
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115

    测试使用JavaCodeUtil

        public static void main(String[] args) throws ClassNotFoundException {
            // java代码
            String contents = "package com.kaka;\n" +
                    "class Test02 {\n" +
                    "    public static void main(String[] args) {\n" +
                    "\tint i = 0;\n" +
                    "        System.out.println(\"这是Test02的main方法 \"+i);\n" +
                    "    }\n" +
                    "   public void getiii(){}\n" +
                    "}";
            
            // 把字符串编译成class文件
            JavaCodeUtil.codeToClass(contents,getProjectPath()+"target/classes");
            // 加载这个calss文件
            Class<?> aClass = Class.forName("com.kaka.Test02");
            // 获取Test02中的方法
            Method[] methods = aClass.getMethods();
            for (Method method : methods) {
                System.out.println(method.getName());
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
  • 相关阅读:
    Java/ExecutorService中多线程服务ExecuteService的使用
    凉鞋的 Unity 笔记 109. 专题一 小结
    【云原生】Docker环境安装
    百货店失去核心竞争力了吗?全靠超市即时零售撑起
    文件操作之文件下载(32)
    大师偷学:vue-cli构建SPA项目和SPA项目结构
    效率工具:企业微信机器人完成脚本工作-异常监控(sql篇)
    毕业设计之基于springboot+uniapp的租房小程序
    [学习记录] 设计模式 3. 观察者模式
    冒泡排序与选择排序(最low的两兄弟)
  • 原文地址:https://blog.csdn.net/a__int__/article/details/128006581