学习 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. MacOS上通过虚拟机搭建基础CentOS7系统环境

    MacOS上通过虚拟机搭建基础CentOS7系统环境 尽管从Mac的Terminal可以看出,macOS与UNIX.Linux或多或少都有血缘关系(shell.bash等),但是在mac进行Linux ...

  2. 演员 Or 开发者的自我修养

    演员 Or 开发者的自我修养 时至今日,我都还是很怀念小时候与一群玩伴编写剧本.拍摄,那时候的我还有一个远大的"白日梦"--成为一名导演.很可惜,终究是"白日梦" ...

  3. The type name or alias SqlServer could not be resolved.Please check your configuration

    The type name or alias SqlServer could not be resolved.Please check your configuration file.... 检查一下 ...

  4. 市区择房分析(ArcPy实现)

    1, 背景 如何找到环境好.购物方便.小孩上学方便的居住区地段是购房者最关心的问题.因此购房者就需要从总体上对商品房的信息进行研究分析,选择最适宜的购房地段. 2,目的 学会利用缓冲区分析和叠置分析解 ...

  5. django 1.11.16之环境搭建

    django版本:django1.11.16  windows环境 python 3.6.3    !!!可先安装虚拟环境在进行环境搭建  1.安装django:pip install django= ...

  6. 【UE4 C++ 基础知识】<11>资源的同步加载与异步加载

    同步加载 同步加载会造成进程阻塞. FObjectFinder / FClassFinder 在构造函数加载 ConstructorHelpers::FObjectFinder Constructor ...

  7. 计算机网络:HTTP

    计算机网络基础:HTTP 先验知识 HTTP和其他协议的关系 通过下图,了解IP协议,TCP协议,DNS服务在使用HTTP协议通信过程中各自发挥的作用: 服务器处理流程 接受客户端连接 ------& ...

  8. python pip whl安装和使用

    转载:https://www.cnblogs.com/klb561/p/9271322.html 1 python的安装 首先,从python的官方网站 www.python.org下载需要的pyth ...

  9. 2021.11.2-测试T1数独

    痛苦 题目 数 独 [问题描述] 给定一个9*9矩阵,对其进行几种操作,分别是插入,删除,合并,查询,输出 主要学到了一些特别的操作. (1)备份( 本蒟蒻第一次了解到) (2)对与数据的一些特别的改 ...

  10. 线程创建,属性设置与获得,等待线程结束,线程中fork,以及执行exec()

    这篇博客的形式我想以分析代码不同情况为主: 点击(此处)折叠或打开 #include<stdio.h> #include<pthread.h> #include<time ...