在内存中编译java代码
问题
最近有一个需求,在flink程序中接受一段java源代码,需要在flink程序中编译这段代码并执行,返回执行结果。
很多编译方案都是将java文件和生成的class文件放在临时磁盘上,但flink程序作为一个长期运行的任务,如果监控发现不及时,很可能出现临时目录满了的情况,所以最好做成一个纯内存编译,提升任务的稳定性。 解决方案
jdk中有JavaCompiler接口用来编译java源码,其中getTask方法用来生成一个编译任务。其中的参数,compilationUnits用来表示需要编译的内容;JavaFileManager用来管理各种文件;options用来传递编译的参数(比如-classpath/-d等javac命令的参数)。
所有的文件都用JavaFileObject来表示,因此需要实现自己的类,用内存保存java源码,用内存保存生成的class文件内容。 用内存保存java源码private static class StringSourceSimpleJavaFileObject extends SimpleJavaFileObject { private final String code; StringSourceSimpleJavaFileObject(String name, String code) { super(URI.create("string:///" + name.replace(".", "/") + Kind.SOURCE.extension), Kind.SOURCE); this.code = code; } @Override public CharSequence getCharContent(boolean ignoreEncodingErrors) { return code; } @Override public String toString() { return code; } }用内存保存class文件private static class OutputClassJavaFileObject extends SimpleJavaFileObject { private final ByteArrayOutputStream outputStream; protected OutputClassJavaFileObject(String className, Kind kind) { super(URI.create("mem:///" + className.replace(".", "/") + kind.extension), kind); this.outputStream = new ByteArrayOutputStream(); } public OutputStream openOutputStream() throws IOException { return this.outputStream; } public byte[] getBytes() { return this.outputStream.toByteArray(); } }自定义FileManager
需要一个自定义的FileManager,当生成class文件时,使用自定义类。
需要注意的时,编译一个源码文件时,可能会因为内部类等原因,会生成多个class文件。 private static class FileManager extends ForwardingJavaFileManager { private Map outputs = new LinkedHashMap<>(); FileManager(StandardJavaFileManager target) { super(target); } @Override public JavaFileObject getJavaFileForOutput(Location location, String className, JavaFileObject.Kind kind, FileObject sibling) { final OutputClassJavaFileObject file = new OutputClassJavaFileObject(className, kind); outputs.put(className, file); return file; } public byte[] getOutputClassBytes(String className) { OutputClassJavaFileObject file = outputs.get(className); if (file != null) { return file.getBytes(); } return null; } public Map getOutputClassBytes() { Map result = new LinkedHashMap<>(); for (Map.Entry entry : outputs.entrySet()) { byte[] bytes = entry.getValue().getBytes(); if (bytes != null && bytes.length > 0) { result.put(entry.getKey(), bytes); } } return result; } }调用编译任务public static byte[] compile(String className, String classSource, String classPath) { logger.info("compile, className = {}, classPath = {}, sourceLength = {}", className, classPath, classSource.length()); long start = System.currentTimeMillis(); JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); JavaFileObject file = new StringSourceSimpleJavaFileObject(className, classSource); Iterable<? extends JavaFileObject> compilationUnits = Arrays.asList(file); StandardJavaFileManager standardFileManager = compiler.getStandardFileManager(null, null, null); FileManager fileManager = new FileManager(standardFileManager); DiagnosticCollector diagnostics = new DiagnosticCollector<>(); StringWriter out = new StringWriter(); Iterable options = null; if (classPath != null && classPath.length() > 0) { options = Arrays.asList("-cp", classPath); } JavaCompiler.CompilationTask task = compiler.getTask(out, fileManager, diagnostics, options, null, compilationUnits); boolean success = task.call(); byte[] result = null; if (success) { result = fileManager.getOutputClassBytes(className); logger.info("compile, ok, className = {}", className); } else { logger.error("compile, error, className = {}", className); logger.error("compile, error, className = {}, diagnostics = {}", className, formatDiagnostics(diagnostics)); } logger.info("compile, className = {}, success = {}, cost = {} ms, byteCodeLength = {}", className, success, System.currentTimeMillis() - start, result == null ? 0 : result.length); return result; }参考
https://stackoverflow.com/questions/7989135/is-it-possible-to-programmatically-compile-java-source-code-in-memory-only
https://docs.oracle.com/javase/7/docs/api/javax/tools/JavaCompiler.html
从中专生到首富,一个千亿金控帝国的崛起与毁灭2021年9月29日,九鼎投资发布公告,其董事长吴刚,涉嫌违反基金相关法律法规,被证监会立案调查。早在今年1月,九鼎投资因曾经操控5个证券账户,交易九鼎投资的股票,非法获利5亿元,
遍地足疗店,为何洗不出一家大公司?几乎所有的足疗店,一旦开始壮大,都无法挽回地走向分崩离析。2018年1月10日,互联网筹款平台轻松筹上悄然多了一个重病求助者。这位求助者叫富侨四哥,他称自己肝硬化晚期,急需肝移植手
马斯克最大对手!他37岁把公司卖给马云,套现300亿后创业2020年的广州车展上,小鹏汽车宣布将率先在全球推出首款搭载激光雷达的量产智能汽车时,特斯拉CEO埃隆马斯克发推称,小鹏汽车使用的是特斯拉旧版本软件,并且还偷了苹果公司的代码。当然
千兆智家套餐便宜一多半,全家越用越划算电信美好家放大招啦现在办理电信美好家十全十美5G畅享融合套餐礼包版,全家即刻共享千兆5G千兆宽带千兆WiFi,畅快三千兆美好体验!还有播播宝盒综艺包天翼云盘黄金会员视频彩铃心动会员
3步教你,百度网盘下载不限速,比SVIP速度还要快使用百度网盘的时候,怎么提升下载速度呢?除了开通会员,你还有什么办法吗?今天小编通过它,实测百度网盘的下载速度达到三四十兆每秒,有时还能比开了超级会员的速度还要快!接下来小编详细跟
杰长老推荐唱片室内乐曲目及唱片二十张(下)多音乐爱好者在面对如云烟一般的古典音乐曲目和唱片都会很苦恼,不知道该如何选择。因此自己整理了这个系列的文章,给广大音乐爱好者按系列推荐各二十张唱片方便音乐爱好者入门。主要以古典音乐
户外艺术展PiedmontArtWalk视觉形象升级PiedmontArtWalk最早于2020年举办,是一项年度活动,展示居住在美国加州皮埃蒙特的艺术家的多样性。在春天,皮埃蒙特整个城市的人行道花园和草坪都会被改造成适合步行的户外
爱威影音邀您共赏2020南宁国际视听展自从2006年以来,每年金秋时节都让众多的广西音乐电影爱好者和音响发烧友们倍加期待,因为一年一度的南宁(东盟)国际视听展都会在这美好的季节里如期举办。历经14届的南宁国际视听展,以
爷爷奶奶带孩子,这些话最好不要说点关注不迷路和父母统一教育理念,不要做孩子的保护伞如今,社会的压力也越来越大,年轻的父母也天天因为忙于工作,社交来不及要孩子,生下孩子也会因为工作的原因,不能一直照顾,所以带孩子往
穿越星河遇见SensaSound胜赏专业家庭影院随着电影市场的崛起带动了家庭影院的发展,越来越多人会打造专属家庭影院,从最初的5。17。110。111。1等系统发展到Auro3D环绕声技术,让观众能够感受到更逼真包围感更强且更震
美女姐姐视频带你了解FOCAL全新乌托邦极品定制影院法国音响品牌Focal,因为乌托邦UTOPIA这个绚丽的名字在HiFi音响界大名鼎鼎,在先后推出至尊乌托邦落地喇叭和乌托邦耳机后,在2021年Focal再次推出令人难以置信的乌托邦