• Java_动态编译总结


    不多说直接上代码:

    动态编译的主类:

    package com.lkb.autoCode.util;
    
    import com.lkb.autoCode.constant.AutoCodeConstant;
    import org.apache.commons.logging.Log;
    import org.apache.commons.logging.LogFactory;
    
    import javax.tools.*;
    import java.io.File;
    import java.io.FileFilter;
    import java.io.IOException;
    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.List;
    
    
    /**
     * AutoCompiler 动态编译器
     *
     * @author Lilin
     * @date 2016/5/18
     */
    public class AutoCompiler {
        private static final Log log = LogFactory.getLog(AutoCompiler.class);
    
        /**
         * Description: Compile java source file to java class with run method
         *
         * @param fullFileName the java source file name with full path
         * @return true-compile successfully, false - compile unsuccessfully
         */
        public static boolean compileFile(String fullFileName) {
            boolean bRet = false;
            // get compiler
            JavaCompiler oJavaCompiler = ToolProvider.getSystemJavaCompiler();
            // compile the java source code by run method
            int iCompileRet = oJavaCompiler.run(null, null, null, fullFileName);
            // set compile result
            if (0 == iCompileRet) {
                bRet = true;
            }
            return bRet;
        }
    
        /**
         * Description: Compile java source file to java class with getTask
         * method, it can specify the class output path and catch diagnostic
         * information
         *
         * @param fullFileName the java source file name with full path
         * @param outputPath   the output path of java class file
         * @return true-compile successfully, false - compile unsuccessfully
         * @throws IOException
         */
        public static boolean compileFile(String fullFileName, String outputPath) {
            System.out.println("源文件路径:" + fullFileName);
            System.out.println("输入路径:" + outputPath);
            boolean bRet = false;
            // get compiler
            // TODO 当运行环境是JRE是无法直接ToolProvider.getSystemJavaCompiler();这么获取
            JavaCompiler oJavaCompiler = ToolProvider.getSystemJavaCompiler();
    
            // define the diagnostic object, which will be used to save the diagnostic information
            DiagnosticCollector<JavaFileObject> oDiagnosticCollector = new DiagnosticCollector<JavaFileObject>();
    
            // get StandardJavaFileManager object, and set the diagnostic for the object
            StandardJavaFileManager oStandardJavaFileManager = oJavaCompiler
                    .getStandardFileManager(oDiagnosticCollector, null, null);
    
            // set class output location
            JavaFileManager.Location oLocation = StandardLocation.CLASS_OUTPUT;
            try {
                File outputFile = new File(outputPath);
                if (!outputFile.exists()) {
                    outputFile.mkdir();
                }
                List<File> dependencies = new ArrayList<File>();
    
                // 加载依赖的jar文件
                dependencies.addAll(getJarFiles(AutoCodeConstant.JARS_PATH));
                // 加载依赖的class文件
                dependencies.add(new File(AutoCodeConstant.BASE_PATH));
    
    
                oStandardJavaFileManager.setLocation(StandardLocation.CLASS_PATH, dependencies);
                oStandardJavaFileManager.setLocation(oLocation, Arrays
                        .asList(new File[]{outputFile}));
    
                File sourceFile = new File(fullFileName);
                // get JavaFileObject object, it will specify the java source file.
                Iterable<? extends JavaFileObject> oItJavaFileObject = oStandardJavaFileManager
                        .getJavaFileObjectsFromFiles(Arrays.asList(sourceFile));
                // -g 生成所有调试信息
                // -g:none 不生成任何调试信息
                // -g:{lines,vars,source} 只生成某些调试信息
                // -nowarn 不生成任何警告
                // -verbose 输出有关编译器正在执行的操作的消息
                // -deprecation 输出使用已过时的 API 的源位置
                // -classpath <路径> 指定查找用户类文件的位置
                // -cp <路径> 指定查找用户类文件的位置
                // -sourcepath <路径> 指定查找输入源文件的位置
                // -bootclasspath <路径> 覆盖引导类文件的位置
                // -extdirs <目录> 覆盖安装的扩展目录的位置
                // -endorseddirs <目录> 覆盖签名的标准路径的位置
                // -d <目录> 指定存放生成的类文件的位置
                // -encoding <编码> 指定源文件使用的字符编码
                // -source <版本> 提供与指定版本的源兼容性
                // -target <版本> 生成特定 VM 版本的类文件
                // -version 版本信息
                // -help 输出标准选项的提要
                // -X 输出非标准选项的提要
                // -J<标志> 直接将 <标志> 传递给运行时系统
    
                // 编译选项,将编译产生的类文件放在当前目录下
                //Iterable<String> options = Arrays.asList("-encoding", AutoCodeConstant.CONTENT_ENCODING, "-classpath", getJarFiles(AutoCodeConstant.JARS_PATH));
                Iterable<String> options = Arrays.asList("-encoding", AutoCodeConstant.CONTENT_ENCODING);
                // compile the java source code by using CompilationTask's call method
                bRet = oJavaCompiler.getTask(null, oStandardJavaFileManager,
                        oDiagnosticCollector, options, null, oItJavaFileObject).call();
    
                //print the Diagnostic's information
                for (Diagnostic oDiagnostic : oDiagnosticCollector
                        .getDiagnostics()) {
    //                log.info("Error on line: "
    //                        + oDiagnostic.getLineNumber() + "; URI: "
    //                        + oDiagnostic.getSource().toString());
                    System.out.printf(
                            "Code: %s%n" +
                                    "Kind: %s%n" +
                                    "Position: %s%n" +
                                    "Start Position: %s%n" +
                                    "End Position: %s%n" +
                                    "Source: %s%n" +
                                    "Message: %s%n",
                            oDiagnostic.getCode(), oDiagnostic.getKind(),
                            oDiagnostic.getPosition(), oDiagnostic.getStartPosition(),
                            oDiagnostic.getEndPosition(), oDiagnostic.getSource(),
                            oDiagnostic.getMessage(null));
                }
            } catch (IOException e) {
                log.error("动态编译出现异常", e);
            } finally {
                //close file manager
                if (null != oStandardJavaFileManager) {
                    try {
                        oStandardJavaFileManager.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                        log.error("动态编译关闭文件管理器出现异常", e);
                    }
                }
            }
            return bRet;
        }
    
        /**
         * 查找该目录下的所有的jar文件
         *
         * @param jarPath
         * @throws Exception
         */
        private static List<File> getJarFiles(String jarPath) {
            final List<File> dependencyJars = new ArrayList<File>();
            File sourceFile = new File(jarPath);
            if (sourceFile.exists()) {// 文件或者目录必须存在
                if (sourceFile.isDirectory()) {// 若file对象为目录
                    // 得到该目录下以.java结尾的文件或者目录
                    File[] childrenFiles = sourceFile.listFiles(new FileFilter() {
                        public boolean accept(File pathname) {
                            if (pathname.isDirectory()) {
                                return true;
                            } else {
                                String name = pathname.getName();
                                if (name.endsWith(".jar") ? true : false) {
                                    //jars[0] = jars[0] + pathname.getPath() + ";";
                                    dependencyJars.add(pathname);
                                    return true;
                                }
                                return false;
                            }
                        }
                    });
                }
            }
            return dependencyJars;
        }
    }

    辅助类:

    package com.lkb.autoCode.constant;
    
    /**
     * AutoCodeConstant
     *
     * @author Lilin
     * @date 2016/5/18
     */
    public class AutoCodeConstant {
        /**
         * 登录模板名称
         */
        public static String LOGIN_TEMPLATE_FTL = "LoginClientTemplate.ftl";
        /**
         * 项目根路径
         */
        public final static String BASE_PATH = AutoCodeConstant.class.getResource("/").toString().replaceAll("^file:/", "");
    
        /**
         * Jar包所在目录
         */
        public final static String JARS_PATH = BASE_PATH.replace("classes","lib");
        /**
         * 模板根路径
         */
        public final static String BASE_TEMPLATE_PATH = BASE_PATH + "template";
        /**
         * client目录
         */
        public final static String LOCAL_CLIENT_BASE_PATH = "src/main/java/com/lkb/sb/client/";
        /**
         * client目录
         */
        public final static String CLIENT_BASE_PATH = "com/lkb/sb/client/";
        /**
         * client类名后缀
         */
        public final static String LOGIN_CLIENT_SUFFIX = "LoginClient.java";
        /**
         * 默认编译输出路径
         */
        public final static String DEFULT_OUTPUT_PATH = "/";
        /**
         * 编码格式
         */
        public final static String CONTENT_ENCODING = "UTF-8";
    
    
    }

    开发背景:需求是根据代码模板动态生成java代码,并动态编译

    开发过程中遇到的阻塞:模板代码中有依赖别的class文件和jar文件无法加载的问题

    解决方法:

    // 加载依赖的jar文件
    dependencies.addAll(getJarFiles("jar文件的根路径"));
    // 加载依赖的class文件
    dependencies.add(new File("class文件的根路径"));
    
    
    
        /**
         * 查找该目录下的所有的jar文件
         *
         * @param jarPath
         * @throws Exception
         */
        private static List<File> getJarFiles(String jarPath) {
            final List<File> dependencyJars = new ArrayList<File>();
            File sourceFile = new File(jarPath);
            if (sourceFile.exists()) {// 文件或者目录必须存在
                if (sourceFile.isDirectory()) {// 若file对象为目录
                    // 得到该目录下以.java结尾的文件或者目录
                    File[] childrenFiles = sourceFile.listFiles(new FileFilter() {
                        public boolean accept(File pathname) {
                            if (pathname.isDirectory()) {
                                return true;
                            } else {
                                String name = pathname.getName();
                                if (name.endsWith(".jar") ? true : false) {
                                    //jars[0] = jars[0] + pathname.getPath() + ";";
                                    dependencyJars.add(pathname);
                                    return true;
                                }
                                return false;
                            }
                        }
                    });
                }
            }
            return dependencyJars;
        }
  • 相关阅读:
    Get https://registry-1.docker.io/v2/: net/http: request canceled while waiting for connection (Clien
    docker pull下载镜像报错Get https://registry-1.docker.io/v2/library/centos/manifests/latest:..... timeout
    Maven 插件之 docker-maven-plugin 的使用
    Windows10下的docker安装与入门 (一)使用docker toolbox安装docker
    解决IntelliJ IDEA 创建Maven项目速度慢问题
    svn检出maven项目的步骤
    学习RabbitMQ(三):AMQP事务机制
    TX-LCN分布式事务Demo实战
    SQLite -创建数据库
    备忘录模式
  • 原文地址:https://www.cnblogs.com/gisblogs/p/5512370.html
Copyright © 2020-2023  润新知