学习 xxl-job 定时任务时了解到基于 JVM 的 Grovvy 脚本语言、搭建 Jenkins 时知道了编译API

1. Java 脚本机制

Java 的脚本 API 可以让我们调用 JavaScript、Grovvy、Ruby 等脚本语言,它避免了编译和链接环节,具有如下优势:

  • 可快速变更,不断实验(Java 9 已经有 JShell 可以实验了)
  • 可修改运行着的程序行为
  • 支持程序定制化

1.1 使用示例

public static void main(String[] args) throws Exception {

    // 获取 JS 脚本引擎
ScriptEngineManager scriptEngineManager = new ScriptEngineManager();
ScriptEngine jsEngine = scriptEngineManager.getEngineByName("JS"); // 执行脚本语言
String script = "var num = 1 + 2";
jsEngine.eval(script); // 也可以从流中获取脚本
FileInputStream fileInputStream = new FileInputStream(new File("script.txt"));
InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream);
jsEngine.eval(inputStreamReader); // 绑定变量
jsEngine.put("testKey", "testValue"); // 执行方法
// 脚本引擎调用方法需要实现 Invocable 接口
String jsMethod = "function hello() {return 'Hello World'}";
jsEngine.eval(jsMethod);
Object function = ((Invocable) jsEngine).invokeFunction("hello"); // 获取结果
Object num = jsEngine.get("num");
Object testValue = jsEngine.get("testKey");
System.out.println(num.toString());
System.out.println(testValue.toString());
System.out.println(function.toString());
}

1.2 思考

脚本语言不像 Java 修改代码后需要再次编译和部署,这样想想的话 xxl-job 定时任务框架可能是通过 RPC 调用传输了 Grovvy 脚本的流给执行器,那么 JVM 执行的定时任务都是最新的

脚本 API 允许从外部读取脚本且实时生效,那么就可以做插件式的功能接口,只需做一个公用接口或者上层抽象类来调用外部脚本,需定制化或修改时可替换外部脚本来实现

2. 编译器 API

在项目中也看到过用 Java 来写 Java 类然后编译放入项目中调用的,第一次见有点新鲜感。这个编译器 API 在测试和自动化构建中也会被调用

2.1 基本使用

默认编译之后的字节码在同级目录下

public class CompilerTest1 {
public static void main(String[] args) { // 获取编译器
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); /**
* 参数分别是
* InputStream in:输入流规定为空,默认的编译器不会接收控制台输入
* OutputStream out:输出,为空输出到控制台
* OutputStream err:输出,为空输出到控制台
* String... arguments:参数,若调用 javac 则是传入启动参数
* result:返回 0 则编译成功
*/
int result = compiler.run(null, null, null, "D:\\CompilerTest.java"); if (result == 0) {
System.out.println("编译成功");
} else {
System.out.println("编译失败");
}
}
}

2.2 实际事例

项目中编译的情况相对来说是复杂些,需要发起编译任务来对编译过程有更多的控制

public class CompilerTest2 {

    public static void main(String[] args) throws URISyntaxException, IllegalAccessException, InstantiationException, NoSuchMethodException, ClassNotFoundException, InvocationTargetException {

        // 获取编译器
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); // 类名、字符串的类代码
String className = "TestClass";
StringBuilder sb = new StringBuilder();
sb.append("public class TestClass {\n");
sb.append("\tpublic void hello() {\n");
sb.append("\t\tSystem.out.println(\"Hello World Compiler\");\n");
sb.append("\t}\n");
sb.append("}"); // 将字符串代码转成 JavaFileObject ———— 编译器需要
StringSource javaFileObject = new StringSource(className, sb.toString());
Iterable<StringSource> fileObjects = Arrays.asList(javaFileObject); // 文件管理器 ———— 编译器需要
StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null); // 报告诊断信息对象 ———— 编译器需要
DiagnosticCollector<JavaFileObject> diagnosticCollector = new DiagnosticCollector<JavaFileObject>(); // 编译参数:编译后的字节码输出地址
File classPath = new File(Thread.currentThread().getContextClassLoader().getResource("").toURI());
String outDir = classPath.getAbsolutePath() + File.separator;
Iterable<String> options = Arrays.asList("-d", outDir); /**
* Writer out:输出,为空到控制台
* JavaFileManager fileManager:文件管理器,为空用编译器的标准文件管理器
* DiagnosticListener<? super JavaFileObject> diagnosticListener:诊断监听器,为空用编译器默认方法报告
* Iterable<String> options:编译参数
* Iterable<String> classes:需要编译的类,用于注解处理
* Iterable<? extends JavaFileObject> compilationUnits
*/
JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager, diagnosticCollector, options, null, fileObjects); // 执行编译
boolean result = task.call(); // 编译错误信息
if (result != true) {
for (Diagnostic diagnostic : diagnosticCollector.getDiagnostics()) {
System.out.println("Error on line: " + diagnostic.getLineNumber());
System.out.println("URI: " + diagnostic.getSource().toString());
}
System.exit(-1);
} // 将字节码加载进 JVM
Class<?> clazz = Class.forName(className); // 创建一个新类,反射执行其方法
Object instance = clazz.newInstance();
Method helloMethod = clazz.getMethod("hello");
helloMethod.invoke(instance);
} /**
* 字符串的类代码存在于内存之中,而参数需要 FileObject
* 我们将字符串代码转成 FileObject 类型
*/
static class StringSource extends SimpleJavaFileObject {
private String code; StringSource(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;
} public String getCode() {
return code;
}
}
}

Java的脚本机制、编译器API的更多相关文章

  1. Java SE 6 新特性: 编译器 API

    新 API 功能简介 JDK 6 提供了在运行时调用编译器的 API,后面我们将假设把此 API 应用在 JSP 技术中.在传统的 JSP 技术中,服务器处理 JSP 通常需要进行下面 6 个步骤: ...

  2. Java学习笔记--脚本语言支持API

    Java语言的动态性之脚本语言支持API 随着Java平台的流行,很多的脚本语言(scripting language)都可以运行在Java虚拟机啊上,其中比较流行的有JavaScript.JRuby ...

  3. Java编译器API简介

    今天给大家分享的是Java编译器API简介,文章部分内容摘自[优锐课]学习笔记. Java编译器API Java编译器API是Java模块(称为java.compiler)的一部分.该模块包括语言模型 ...

  4. Java中JIN机制及System.loadLibrary() 的执行过程

    Android平台Native开发与JNI机制详解 http://mysuperbaby.iteye.com/blog/915425 个人认为下面这篇转载的文章写的很清晰很不错. 注意Android平 ...

  5. java虚拟机运行机制

    转自java虚拟机运行机制 首先简单阐述下解释型语言和编译型语言的联系与区别. 编译型语言是通过编译器将程序编译成目标机器所能识别的机器码,而解释型语言不需要编译过程.由该语言的解释器读取脚本,按照语 ...

  6. 深入研究Java类载入机制

    深入研究Java类载入机制   类载入是Java程序运行的第一步,研究类的载入有助于了解JVM运行过程,并指导开发人员採取更有效的措施配合程序运行. 研究类载入机制的第二个目的是让程序能动态的控制类载 ...

  7. Java高新技术 反射机制

     Java高新技术 反射机制 知识概要:                   (1)反射的基石 (2)反射 (3)Constructor类 (4)Field类 (5)Method类 (6)用反射方 ...

  8. java的运行机制(基础)

    1:高级语言的运行机制: 我们编程都是用的高级语言(写汇编和机器语言的大牛们除外),计算机不能直接理解高级语言,只能理解和运行机器语言,所以必须要把高级语言翻译成机器语言,计算机才能运行高级语言所编写 ...

  9. Java 的异常处理机制

    异常是日常开发中大家都「敬而远之」的一个东西,但实际上几乎每种高级程序设计语言都有自己的异常处理机制,因为无论你是多么厉害的程序员,都不可避免的出错,换句话说:你再牛逼,你也有写出 Bug 的时候. ...

随机推荐

  1. Tomcat各种日志的关系与catalina.out文件的分割

    Tomcat 各日志之间的关系 一图胜千言! 其他日志如localhost.{yyyy-MM-dd}.log.localhost-access.{yyyy-MM-dd}.log是context的名称, ...

  2. web全栈后台权限管理系统(VUE+ElementUi+nodeJs+koa2)

    web全栈后台权限管理系统(VUE+ElementUi+nodeJs+koa2) 主要技术 前端 vue 全家桶 ElementUI 后端 Node.js Koa2 Mongoess 数据库 mong ...

  3. Java(1)开发环境配置及第一个程序Hello World

    作者:季沐测试笔记 原文地址:https://www.cnblogs.com/testero/p/15201468.html 博客主页:https://www.cnblogs.com/testero ...

  4. Java(20)参数传递之类名、抽象类、接口

    作者:季沐测试笔记 原文地址:https://www.cnblogs.com/testero/p/15201632.html 博客主页:https://www.cnblogs.com/testero ...

  5. C# 提取PDF中的表格

    本文介绍在C#程序中(附VB.NET代码)提取PDF中的表格的方法,调用Spire.PDF for .NET提供的提取表格的类以及方法等来获取表格单元格中的文本内容:代码内容中涉及到的主要类及方法归纳 ...

  6. NX开发库版本问题

    有做NX二次开发的朋友经常问我这样的问题:我在NX8.0上开发的程序,可以在NX9.0上运行吗? 由于NX的开发库随着版本的更新也会不断更新,会增加新的方法,同时有些也会过时或者消失. 如下图:NX8 ...

  7. 款阿里开源的 Java 诊断工具Arthas

    Arthas是什么鬼? Arthas是一款阿里巴巴开源的 Java 线上诊断工具,功能非常强大,可以解决很多线上不方便解决的问题. Arthas诊断使用的是命令行交互模式,支持JDK6+,Linux. ...

  8. SharkCTF2021 BabyGame

    web类题. 访问题给页面,页面里没啥信息.抓包,发现: 访问它,发现是一个游戏. F12之后看调试器里的js代码,发现: console.log("balabalabala"); ...

  9. HCNP Routing&Switching之BGP防环机制和路由聚合

    前文我们了解了BGP路由宣告相关话题,回顾请参考https://www.cnblogs.com/qiuhom-1874/p/15440860.html:今天我们来聊一聊BGP防环机制和路由聚合相关话题 ...

  10. 网络原理数据链路层之差错控制(检错编码和纠错编码)->(奇偶校验码、CRC循环冗余码、海明码)

    文章转自:https://blog.csdn.net/weixin_43914604/article/details/104864783 学习课程:<2019王道考研计算机网络> 学习目的 ...