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;
    }
时间: 2024-10-09 17:16:11

Java_动态编译总结的相关文章

ANGULARJS 动态编译添加到dom中

在使用angularjs 时,希望通过动态构建angular模版,再通过angular进行展示. 使用 方法如下: <html ng-app="app"> <head> <meta http-equiv="content-type" content="text/html; charset=utf-8" /> <script src="assets/angular.min.js">

程序动态编译代码

c#可以在程序运行过程中动态的编译代码,并生成程序集加载在内存,然后就可以动态的调用代码生成的程序了,这有点像我们的vs编译器,感兴趣的可以制作属于自己的c#编译器: 要实现这种功能,我们只需要调用CSharpCodeProvider就可以实现了: string prefix = "using System;"+ "public static class Test{"+ "public static void Run(){"; string po

nginx php动态编译加载模块.

#Nginx动态编译加载模块步骤 #查看目前Nginx版本及编译模块 #[[email protected] ~]# /opt/app/lnmp/nginx-1.12.0/sbin/nginx -V #nginx version: nginx/1.12.0 #built by gcc 4.8.5 20150623 (Red Hat 4.8.5-11) (GCC) #built with OpenSSL 1.0.2k  26 Jan 2017 #TLS SNI support enabled #c

浅谈VB.Net 程序的编译和动态编译

---恢复内容开始--- 一般,我们都是通过Visual Studio(下面简称vs)来编写和编译vb.net应用程序的,但是,不少的人并不知道vs是通过何种方式编译程序的.今天,我们就来探讨一下编译vb.net程序的真正原理. 这篇随笔包含如下几个部分: 1.VS是怎么编译的 2.通过vbc.exe来编译应用程序 3.在代码中通过VBCodeProvider动态编译应用程序 ok,首先来说说vs编译应用程序的方法.其实,vs是通过调用vbc.exe来编译vbnet应用程序的.vs把用户编写的代

动态编译添加php模块

注意:转载请注明出处:http://www.programfish.com/blog/?p=85 在很多时候我们用linux里搭建web服务器的时候会需要编译安装php套件,而在编译安装后可能又会需要添加一些编译安装时没有指定要编译进去的模块,例如如下情况: mysql.so 或mysqli.so .mbstring.so  zlib.so 等模块. 这里提示一下: 如果你有安装过phpmyadmin而且在安装配置好之后打开首页是空白的,那么很有可能就是你的php没有mysql和mbstring

Apache静态编译与动态编译区别

静态编译: 在编译时,已经把相关模块编译进httpd二进制文件中不用再 httpd.conf 中在 LoadModule 来加载,只要在  <ifmodule></ifmodule> 中来配置就可以了. 动态编译: 编译的时候,使用 enable-module=shared  或者 enable-modules-shared=module 来动态编译. 动态显然就不编译到httpd里面去了,启动的时候根本不会加载这个模块, 而是给你一个 module.so  文件.你想用,就在ht

动态编译

动态编译.NET代码 分为VB和C#两种 Private Sub BuidSub(OneSource As String, OneRef As String, OneExt As String, OneSub As String, OneClass As String) Dim strSourceCode As String = OneSource Dim objCSharpCodePrivoder As New CSharpCodeProvider() Dim objVBCodePrivode

反射已经&quot;Out&quot;,动态编译才能&quot;Hold&quot;住

Net支持反射功能以后,确实使我们Net程序眼前一亮啊,真是太神奇了,只需要传入字符串就可以完成功能.可以说,反射功能的引入,使我们在处理某些问题上更加得心应手. 传统的Db管理软件中,数据库字段的频繁改动,前台实体类的不断修改,使我们大为头痛.并不是说我们设计的Db结构不合理,而且客户的需求变动十分频繁,而且非常不可控,当然,如果对行业业务非常精通的话,是可以避免这个问题的. 使用反射功能,虽然可以传入字符串来解决某些问题,但如果遇到上述提到的数据库字段增删的问题,我们常用的方法是写入给客户升

gcc 动态编译 动态库路径

gcc 动态编译(共享库) 动态编译的可执行文件需要附带一个的动态链接库,在执行时,需要调用其对应动态链接库中的命令优点:体积小,编译快缺点:依赖性高 代码如下: [[email protected] shared]# cat add.cint add (int x, int y) {return x + y;} Parsed in 0.007 seconds at 12.13 KB/sadd.c 求和函数 代码如下: [[email protected] shared]# cat print.