eclipse编译java项目class文件_动态编译 Java 代码以及生成 Jar 文件

导读: 最近在看 Flink 源码的时候发现到一段实用的代码,该代码实现了 java 动态编译以及生成 jar 文件。将其进行改进后可以应用到我们的平台上,实现在平台页面上编写 java 代码语句,提交后由后台进行编译和打成 Jar 包再上传到指定的文件存储系统,从而代替之前在本地自己手动打 UDF 包的方式。下面我将对这段代码做一些简单分析,希望对各位有所帮助。

00f6bf1e5642a8abd4546f6b3eaa99f7.png

核心代码

public class TestUserClassLoaderJar {    private static final String GENERATED_UDF_CLASS = "LowerUDF";    private static final String GENERATED_UDF_CODE =            "public class " + GENERATED_UDF_CLASS + " extends extends org.apache.flink.table.functions.ScalarFunction {" +                    "  public String eval(String str) {" +                    "    return str.toLowerCase();" +                    "  }" +                    "}";    /**     * 将生成的 UDF class 打包到 JAR 中并且返回 JAR 所在的路径.     */    public static File createJarFile(File tmpDir, String jarName) throws IOException {        // 创建一个 java 文件        File javaFile = Paths.get(tmpDir.toString(), GENERATED_UDF_CLASS + ".java").toFile();        javaFile.createNewFile();        // 将代码写入 java 文件中        FileUtils.writeFileUtf8(javaFile, GENERATED_UDF_CODE);        // 编译 java文件生成 class 文件        DiagnosticCollector diagnostics = new DiagnosticCollector<>();        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();        StandardJavaFileManager fileManager = compiler.getStandardFileManager(diagnostics, null, null);        Iterable extends JavaFileObject> compilationUnit =                fileManager.getJavaFileObjectsFromFiles(Collections.singletonList(javaFile));        JavaCompiler.CompilationTask task = compiler.getTask(                null,                fileManager,                diagnostics,                Collections.emptyList(),                null,                compilationUnit);        // 此处结果返回一个布尔值,可用于判断是否编译成功及是否执行下面的打包操作        task.call();         // 将 class 文件打包到 Jar 中        File classFile = Paths.get(tmpDir.toString(), GENERATED_UDF_CLASS + ".class").toFile();        File jarFile = Paths.get(tmpDir.toString(), jarName).toFile();        JarOutputStream jos = new JarOutputStream(new FileOutputStream(jarFile));        JarEntry jarEntry = new JarEntry(GENERATED_UDF_CLASS + ".class");        jos.putNextEntry(jarEntry);        byte[] classBytes = FileUtils.readAllBytes(classFile.toPath());        jos.write(classBytes);        jos.closeEntry();        jos.close();        return jarFile;    }    public static void main(String[] args) throws IOException {        createJarFile(new File("G:jarSave"),"test.jar");    }}

以上代码主要完成以下三步操作:

  • 创建一个 .java 文件,并将外部输入的 java 语句写入到该文件中
  • 对 java 文件进行编译并生成 class 文件
  • 将 class 文件打包到 JAR 中并返回 JAR 的路径

下图是动态编译的几个关键类的创建方式及作用:

4428adf2bc53f39f5b0e5f2da76056e7.png

JavaCompiler 的由来

在上面代码中通过 ToolProvider.getSystemJavaCompiler() 获取到 JavaCompiler。深入内部 findSystemToolClass() 方法发现其最终先是通过 System.getProperty("java.home") 获取到 /jdk1.8.0_241/jre 目录,再获取其上级目录中 lib 目录下的 tools.jar(也就是/jdk1.8.0_241/lib/ tools.jar),并进行动态加载 Jar 获取到 JavaCompiler。

aeaa3a3bcc4c5f6a911ab8180e2b3f89.png
93954e9701d48f9e459d73a44ce38f16.png

findSystemToolClass 代码片段:

private Class> findSystemToolClass(String toolClassName)        throws MalformedURLException, ClassNotFoundException    {        // try loading class directly, in case tool is on the bootclasspath        try {            return Class.forName(toolClassName, false, null);        } catch (ClassNotFoundException e) {            trace(FINE, e);            // if tool not on bootclasspath, look in default tools location (tools.jar)            ClassLoader cl = (refToolClassLoader == null ? null : refToolClassLoader.get());            if (cl == null) {                File file = new File(System.getProperty("java.home"));                if (file.getName().equalsIgnoreCase("jre"))                    file = file.getParentFile();                for (String name : defaultToolsLocation)                    file = new File(file, name);                // if tools not found, no point in trying a URLClassLoader                // so rethrow the original exception.                if (!file.exists())                    throw e;                URL[] urls = { file.toURI().toURL() };                trace(FINE, urls[0].toString());                cl = URLClassLoader.newInstance(urls);                refToolClassLoader = new WeakReference(cl);            }            return Class.forName(toolClassName, false, cl);        }    }

补充:FileUtils 工具类(已删减,只保留所需部分)

public class FileUtils {    public static void writeFileUtf8(File file, String contents) throws IOException {        writeFile(file, contents, "UTF-8");    }    public static void writeFile(File file, String contents, String encoding) throws IOException {        byte[] bytes = contents.getBytes(encoding);        Files.write(file.toPath(), bytes, new OpenOption[]{StandardOpenOption.WRITE});    }    private static byte[] read(InputStream source, int initialSize) throws IOException {        int capacity = initialSize;        byte[] buf = new byte[initialSize];        int nread = 0;        while (true) {            int n;            while ((n = source.read(buf, nread, Math.min(capacity - nread, 4096))) > 0) {                nread += n;            }            if (n < 0 || (n = source.read()) < 0) {                return capacity == nread ? buf : Arrays.copyOf(buf, nread);            }            if (capacity <= 2147483639 - capacity) {                capacity = Math.max(capacity << 1, 4096);            } else {                if (capacity == 2147483639) {                    throw new OutOfMemoryError("Required array size too large");                }                capacity = 2147483639;            }            buf = Arrays.copyOf(buf, capacity);            buf[nread++] = (byte) n;        }    }    public static byte[] readAllBytes(Path path) throws IOException {        SeekableByteChannel channel = Files.newByteChannel(path);        Throwable var2 = null;        byte[] var7;        try {            InputStream in = Channels.newInputStream(channel);            Throwable var4 = null;            try {                long size = channel.size();                if (size > 2147483639L) {                    throw new OutOfMemoryError("Required array size too large");                }                var7 = read(in, (int) size);            } catch (Throwable var30) {                var4 = var30;                throw var30;            } finally {                if (in != null) {                    if (var4 != null) {                        try {                            in.close();                        } catch (Throwable var29) {                            var4.addSuppressed(var29);                        }                    } else {                        in.close();                    }                }            }        } catch (Throwable var32) {            var2 = var32;            throw var32;        } finally {            if (channel != null) {                if (var2 != null) {                    try {                        channel.close();                    } catch (Throwable var28) {                        var2.addSuppressed(var28);                    }                } else {                    channel.close();                }            }        }        return var7;    }}

最后

以上就是动态编译 Java 代码以及生成 Jar 文件的方式。

感谢您的阅读,如果喜欢本文欢迎关注和转发,本头条号将坚持持续分享IT技术知识。对于文章内容有其他想法或意见建议等,欢迎提出共同讨论共同进步。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/434085.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Dx11DemoBase 基类(三) 实例应用 【已实现】【附带源码】

现在我已经到哪了? 读书时&#xff0c;尤其是技术知识书籍&#xff0c; 我一般会担忧自己是否陷得太深&#xff0c; 细节关注得太多&#xff0c; 而忘了整体的过程&#xff1b; 一直以来对Direct3D 很畏惧&#xff0c; 因为太多函数和细节&#xff1b;现在我必须暂缓下&#x…

修改 decimal 默认值为0.00 sql_被经理邀请去“爬山”,只是因为我写错了一条SQL语句?...

作者&#xff1a;isysc1链接&#xff1a;https://juejin.im/post/5f06a2156fb9a07e5f5180df来源&#xff1a;掘金前戏SQL 写的妙&#xff0c;涨薪呱呱叫&#xff01;新来的实习生小杨写了一条 SQL 语句SELECT wx_id from user WHERE wx_id 2当小杨迫不及待准备下班回家的时候&…

JS中关于clientWidth、offsetWidth、scrollWidth

网页可见区域宽&#xff1a; document.body.clientWidth;网页可见区域高&#xff1a; document.body.clientHeight;网页可见区域宽&#xff1a; document.body.offsetWidth (包括边线的宽);网页可见区域高&#xff1a; document.body.offsetHeight (包括边线的宽);网页正文全…

shell 执行失败重试_Uipath 机器人总是运行失败怎么办?

要知道为什么RPA机器人容易失败&#xff0c;首先了解下它和常规的应用系统有哪些区别。常规应用系统&#xff0c;就像程序员自己创造了一个世界、一个域&#xff0c;在这个世界里创造它的人就是主宰。出现BUG的风险是相对可控的&#xff0c;顶多是功能用不了。而RPA项目&#x…

c mysql安装教程视频_MySQL安装教程 - Windows安装MySQL教程 - 小白式安装MySQL教程 - 青衫慧博客...

版权声明本文转发自旧站点萧瑟云日志&#xff0c;近期考虑准备将旧站进行关闭(没有精力维护)&#xff0c;部分文章将会迁移至本站。文章发表于&#xff1a;2017-10-28 12:32:03前言上次给大家带来了SQL Server的小白式安装教程&#xff0c;这次再次带来一个MySQL的小白式安装教…

PJSIP UA分析(1)--PJSUA主函数

1 intmain(intargc, char*argv[])2 {3 do{4 app_restart PJ_FALSE; //PJ_FALSE是一个宏&#xff0c;一旦用户调用pjsua可执行文件进入该循环&#xff0c;那么默认只执行一次退出5 //如果需要再次循环&#xff0c;那么在下面函数中…

锁定表头和固定列(Fixed table head and columns)

前段时间需要这个功能&#xff0c;但是找了很多都不能完美的实现&#xff0c;不是只能锁定表头&#xff0c;就是浏览器兼容问题什么的&#xff0c;在此就自己做了一个锁定表头和列的js方法&#xff0c;依赖于JQuery。 因为方法很简单&#xff0c;就未封装成插件的形式&#xff…

游戏详细设计说明书_宜家的说明书设计脑洞太大了!

平常我们看到的说明书是像这样纯文字解说的或者是规范的文字配图这些说明书一般都是注重文字的上表达而大家熟悉的家居品牌宜家将说明书创意玩出了新境界&#xff01;↓↓↓这不&#xff0c;最近由于全球疫情严峻期间宜家的全新说明书手册搜罗了各种纸上游戏意为帮助大家打发无…

centos删除php_centos如何卸载php

查看php版本php -v查看php相关软件包#rpm -qa|grep php(视频教程推荐&#xff1a;linux视频教程)提示如下&#xff1a;#php-pdo-5.1.6-27.el5_5.3#php-mysql-5.1.6-27.el5_5.3#php-xml-5.1.6-27.el5_5.3#php-cli-5.1.6-27.el5_5.3#php-common-5.1.6-27.el5_5.3#php-gd-5.1.6-27…

cgblib 代理接口原理_Java开发者你还不知道?告诉你Dubbo 的底层原理,面试不再怕...

前言平常我们在构建分布式系统的时候&#xff0c;一般都是基于 Dubbo 技术栈或者是SpringCloud 技术栈来做。早期其实最先比较流行的是Dubbo&#xff0c;我记得我们当时有个部分的老大就是用的是Dubbo 来构建的一个系统&#xff0c;到后面才出来的 SpringCloud&#xff0c;由于…

包含对流环热,热流边界,等温边界的稳态热传导方程的FEM求解。

以下面的问题为例&#xff1a;对于如图所示的平面传热问题&#xff0c; 若上端有给定的热流-2W/m2&#xff0c;即从下往上传输热量&#xff0c;结构下端有确定的温度100&#xff0c;周围介质温度为20&#xff0c;在两侧有换热&#xff0c;换热系数为α100W/㎡/K&#xff0c;热导…

python生成动态二维码实例_python生成动态个性二维码(示例代码)

1 安装工具 2 生成普通二维码 3 带图片的二维码 4 动态 GIF 二维码 5 在Python程序中使用 一、安装 首先在python环境下运行&#xff0c; 打开cmd进入python27 进入scripts 然后在scripts输入命令&#xff1a;pip install myqr二、 生成普通二维码 安装了 myqr 之后&#xff0c…

matlab武汉理工大学数值分析线性函数拟合实验_「首席架构师推荐」数值计算库精选...

这是一个著名的数值库列表&#xff0c;这些库用于软件开发中执行数值计算。它不是一个完整的列表&#xff0c;而是一个包含Wikipedia上文章的数字库列表&#xff0c;很少有例外。典型库的选择取决于一系列不同的需求&#xff0c;例如:期望的特性(例如:大维线性代数、并行计算、…

JSONP跨域原理和jQuery.getJSON用法

JSONP是一个非官方的协议&#xff0c;它允许在服务器端集成Script tags返回至客户端&#xff0c;通过javascript callback的形式实现跨域访问&#xff08;这仅仅是JSONP简单的实现形式&#xff09;。本文主要介绍JSONP跨域原理&#xff0c;一起来看。 JSONP是一个非官方的协议&…

串口输出5v电压_为什么RS485比串口速度快距离远?--谈单端信号与差分信号之差异...

嵌入式系统中&#xff0c;串口、RS485、CAN、网络和USB等都是非常常用的通信方式。但是串口通信速度慢&#xff0c;距离近&#xff0c;为什么转换成RS485后&#xff0c;通信距离和速度都大幅提高了呢&#xff1f;USB也是近距离&#xff0c;为什么速度可以这么快&#xff1f;原因…

IIS7.0站点/虚拟目录中访问共享

目的&#xff1a;实现一个2008serve的IIS的虚拟目录&#xff08;通过网络路径&#xff08;UNC&#xff09;的形式&#xff0c;共享在另外一个2008服务器上&#xff09; 准备工作1.运行组策略编辑器&#xff08;gpedit.msc&#xff09;&#xff1b;找到本地安全策略-本地策略-安…

易语言操作php文本文件,易语言对文本操作的步骤教学

在易语言编程中&#xff0c;我们往往需要对一些文字进行截取或分割出来&#xff0c;如何准确、快速的实现这一目标呢&#xff1f;下面笔者来为大家演示1、首先&#xff0c;我们打开易语言编程软件&#xff0c;点击左上角&#xff0c;新建一个文件&#xff0c;如图所示2、我们点…

xxl-job 执行结果是空_xxljob dotnet core executor执行器开源

DotXxlJob[(github)https://github.com/xuanye/DotXxlJob][https://github.com/xuanye/DotXxlJob] xxl-job的dotnet core 执行器实现&#xff0c;支持XXL-JOB 2.01 XXL-JOB概述[XXL-JOB][1]是一个轻量级分布式任务调度平台&#xff0c;其核心设计目标是开发迅速、学习简单、轻量…

php5.4 windows2003,PHP实战:Windows2003下php5.4安装配置教程(IIS)

《PHP实战&#xff1a;Windows2003下php5.4安装配置教程(IIS)》要点&#xff1a;本文介绍了PHP实战&#xff1a;Windows2003下php5.4安装配置教程(IIS)&#xff0c;希望对您有用。如果有疑问&#xff0c;可以联系我们。PHP教程一、在Windows2003安装IISPHP教程1、首先打开Windo…

foxmail 怎么把邮件格式默认为html_Python SMTP发送邮件-smtplib模块

在进入正题之前&#xff0c;我们需要对一些基本内容有所了解&#xff1a;常用的电子邮件协议有SMTP、POP3、IMAP4&#xff0c;它们都隶属于TCP/IP协议簇&#xff0c;默认状态下&#xff0c;分别通过TCP端口25、110和143建立连接。Python内置对SMTP的支持&#xff0c;该协议支持…