java 自动编译源码-将源代码编译为java代码形式并打包成jar

相信有的朋友会遇到这样的需求:我们希望对于一些引用定制jar包的java文件,通过后台代码的形式,将java源文件编译打包成jar包,最后返回的位置jar包。 目录java 自动编译源码,通过FileInputStream方法,可以在配置前端导入这个jar包!

在某些特定场景下:比如能力开放平台接入SDK,或者多元化RPC框架的客户端SDK,如果我们能够远程调用这个客户端的相关配置文件(比如zk地址,或者token认证码),一起用数据库的方式配置到前端接口,然后通过这种sdk下载方式,就可以快速实现我们平台系统和第三方厂商的快速接入!

话不多说,我们直接上代码吧!

java 自动编译源码-将源代码编译为java代码形式并打包成jar

该组件主要由三部分组成,首先是main方法:


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;
/**
 * 将源码编译后生成jar包
 * @author wenyn
 * @since 2020-05-18
 */
public class BmgJarPackageUtil {
    private static final Log log = LogFactory.getLog(BmgJarPackageUtil.class);
    // 源码路径
    private static String source = ApplicationConfig.getVal("bmg.compile.source");
    // 打jar包的路径
    private static String bin = ApplicationConfig.getVal("bmg.compile.bin");
    // 依赖包路径
    private static String lib = ApplicationConfig.getVal("bmg.compile.lib");
    /**
     * 判断字符串是否为空 有值为true 空为:false
     */
    private static boolean isnull(String str) {
        if (null == str) {
            return false;
        } else if ("".equals(str)) {
            return false;
        } else if (str.equals("null")) {
            return false;
        } else {
            return true;
        }
    }
    /**
     * 编译java文件
     *
     * @param encoding    编译编码
     * @param jars        需要加载的jar
     * @param filePath    文件或者目录(若为目录,自动递归编译)
     * @param sourceDir   java源文件存放目录
     * @param targetDir   编译后class类文件存放目录
     * @param diagnostics 存放编译过程中的错误信息
     * @return
     * @throws Exception
     */
    private static boolean compiler(String encoding, String jars, String filePath, String sourceDir, String targetDir, DiagnosticCollector diagnostics, String sign)
            throws Exception {
        // 获取编译器实例
        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
        // 获取标准文件管理器实例
        StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);
        try {
            if (!isnull(filePath) && !isnull(sourceDir) && !isnull(targetDir)) {
                return false;
            }
            // 得到filePath目录下的所有java源文件
            File sourceFile = new File(filePath);
            List sourceFileList = new ArrayList();
            getSourceFiles(sourceFile, sourceFileList, targetDir, sign);
            // 没有java文件,直接返回
            if (sourceFileList.size() == 0) {
                System.out.println(filePath + "目录下查找不到任何java文件");
                return false;
            }
            // 获取要编译的编译单元
            Iterable compilationUnits = fileManager.getJavaFileObjectsFromFiles(sourceFileList);
            /**
             * 编译选项,在编译java文件时,编译程序会自动的去寻找java文件引用的其他的java源文件或者class。 -sourcepath选项就是定义java源文件的查找目录, -classpath选项就是定义class文件的查找目录。
             */
            Iterable options = Arrays.asList("-encoding", encoding, "-classpath", jars, "-d", targetDir, "-sourcepath", sourceDir);
            JavaCompiler.CompilationTask compilationTask = compiler.getTask(null, fileManager, diagnostics, options, null, compilationUnits);
            // 运行编译任务
            return compilationTask.call();
        } finally {
            fileManager.close();
        }
    }
    /**
     * 查找该目录下的所有的java文件
     *
     * @param sourceFile
     * @param sourceFileList
     * @throws Exception
     */
    private static void getSourceFiles(File sourceFile, List sourceFileList, String targetDir, String sign) throws Exception {
        if (sourceFile.exists() && sourceFileList != null) {//文件或者目录必须存在
            if (sourceFile.isDirectory()) {// 若file对象为目录
                // 得到该目录下以.java结尾的文件或者目录
                File[] childrenFiles = sourceFile.listFiles(new FileFilter() {
                    public boolean accept(File pathname) {
                        if (pathname.isDirectory()) {
                            try {
                                String cpSrc = pathname.getPath();
                                String newTarget = targetDir.substring(0, targetDir.lastIndexOf(sign)-1);
                                String cpTarget = newTarget + pathname.getPath().substring(pathname.getPath().indexOf("src") + 3, pathname.getPath().length());
                                new CopyDirectory().copyDirectiory(cpSrc, cpTarget);
                            } catch (IOException e) {
                                log.error("BmgJarPackageUtil.getSourceFiles--{}文件夹拷贝出现异常...", e);
                                return false;
                            }
                            return true;
                        } else {
                            String name = pathname.getName();
                            if (name.endsWith(".java") ? true : false) {
                                return true;
                            }
                            try {
                                String newTarget = targetDir.substring(0, targetDir.lastIndexOf(sign)-1);
                                String cpTarget = newTarget + pathname.getPath().substring(pathname.getPath().indexOf("src") + 3, pathname.getPath().length());
                                new CopyDirectory().copyFile(pathname, new File(cpTarget));
                            } catch (IOException e) {
                                log.error("BmgJarPackageUtil.getSourceFiles--{}文件拷贝出现异常...", e);
                                return false;
                            }
                            return false;
                        }
                    }
                });
                // 递归调用
                for (File childFile : childrenFiles) {
                    getSourceFiles(childFile, sourceFileList, targetDir, sign);
                }
            } else {// 若file对象为文件
                sourceFileList.add(sourceFile);
            }
        }
    }
    /**
     * 查找该目录下的所有的jar文件
     *
     * @param jarPath
     * @throws Exception
     */
    private static String getJarFiles(String jarPath) throws Exception {
        StringBuilder jarsBuilder = new StringBuilder();
        File sourceFile = new File(jarPath);
        if (sourceFile.exists()) {// 文件或者目录必须存在
            if (sourceFile.isDirectory()) {// 若file对象为目录
                // 得到该目录下以.java结尾的文件或者目录
                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) {
                                jarsBuilder.append(pathname.getPath()).append(";");
                                return true;
                            }
                            return false;
                        }
                    }
                });
            }
        }
        return jarsBuilder.toString();
    }
    /**
     * 获取所有class文件,并将其变为Class对象
     * @param jarFileCreator
     * @param rootDir
     * @param targetDir
     */
    private static void getClass(JarFileCreator jarFileCreator, String rootDir, String targetDir){
        File classDir = new File(targetDir);
        if(classDir.isDirectory()){
            File[] files = classDir.listFiles();
            for(File file :files){
                getClass(jarFileCreator, rootDir, file.getPath());
            }
        } else {
            String name = classDir.getName();
            // class文件才可以加入编译路径
            if(name.endsWith(".class")){
                ThirdClassLoader thirdClassLoader = new ThirdClassLoader(rootDir);
                Class clazz = thirdClassLoader.findClass(targetDir);
                jarFileCreator.addClass(clazz, targetDir);
            }
        }
    }
    /**
     * 将class文件打包成jar包
     * @param jarPath
     * @param bin
     * @throws Exception
     */
    private static void writeNewJar(String jarPath, String bin) throws Exception{
        JarFileCreator jarFileCreator = new JarFileCreator(new File(jarPath));
        getClass(jarFileCreator, bin, bin);
        jarFileCreator.createJarFile();
    }
    /**
     * 将源码打包成jar
     * @param sign
     * @param jarName
     * @throws Exception
     */
    public static String packageJar(String sign, String jarName) throws Exception{
        try {
            String newSource = source + File.separator + sign;
            String newBin = bin + File.separator + sign;
            String newJarPath = newBin + File.separator + jarName;
            DiagnosticCollector diagnostics = new DiagnosticCollector();
            boolean compilerResult = compiler("UTF-8", getJarFiles(lib), newSource, newSource, newBin, diagnostics, sign);
            if (!compilerResult) {
                log.error("BmgJarPackageUtil.compile--{}源码编译失败...");
                for (Diagnostic diagnostic : diagnostics.getDiagnostics()) {
                    log.error("BmgJarPackageUtil.compile--{}" + diagnostic.getMessage(null));
                }
            } else {
                log.info("BmgJarPackageUtil.compile--{}源码编译成功,准备打包..");
                writeNewJar(newJarPath, newBin);
                // 最终返回新生成的jar包路径
                return newJarPath;
            }
        } catch (Exception e) {
            log.error("BmgJarPackageUtil.compile--{}源码编译出现异常..", e);
        }
        return null;
    }
    public static void main(String[] args) {
        try {
            // 生成源码的时候,源码路径必须具备唯一性,防止多个请求同时过来,不同源码之间相互影响
            String path = packageJar("222", "test333.jar");
            System.out.println(path);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

java 自动编译源码-将源代码编译为java代码形式并打包成jar

这个主类有三个主要功能:

1)获取依赖Jar包--getJarFiles

2)获取所有源代码类并复制到目标目录--getSourceFiles

3)编译目标目录下的源代码--compiler

4)获取目标目录下的所有class文件--getClass

6)生成jar包--writeNewJar

java 自动编译源码-将源代码编译为java代码形式并打包成jar

网上提供的jar包大多要么依赖ant,要么依赖maven插件。 少数通过java代码编译的java 自动编译源码,没有纳入jar包流程,只能构建只依赖jdk的项目。 ,功能比较简单。

我在网上找到了很多相关的代码,进行了整理和重新整理,生成了目前最有效的工具代码,并在平台上分享了。 感谢您的浏览!

另外,整体代码,因为明天刚写博客,还没有通过初审。 初审通过后,我会把链接地址贴出来!

本文使用的相关文献如下:

收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

悟空资源网 源码编译 java 自动编译源码-将源代码编译为java代码形式并打包成jar https://www.wkzy.net/game/187107.html

常见问题

相关文章

官方客服团队

为您解决烦忧 - 24小时在线 专业服务