热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Java的脚本机制、编译器API

学习xxl-job定时任务时了解到基于JVM的Grovvy脚本语言、搭建Jenkins时知道了编译API1.Java脚本机制Java的脚本API可以让我们调用JavaScript、

学习 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 fileObjects = Arrays.asList(javaFileObject);
// 文件管理器 ———— 编译器需要
StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);
// 报告诊断信息对象 ———— 编译器需要
DiagnosticCollector diagnosticCollector = new DiagnosticCollector();
// 编译参数:编译后的字节码输出地址
File classPath = new File(Thread.currentThread().getContextClassLoader().getResource("").toURI());
String outDir = classPath.getAbsolutePath() + File.separator;
Iterable optiOns= Arrays.asList("-d", outDir);
/**
* Writer out:输出,为空到控制台
* JavaFileManager fileManager:文件管理器,为空用编译器的标准文件管理器
* DiagnosticListener diagnosticListener:诊断监听器,为空用编译器默认方法报告
* Iterable options:编译参数
* Iterable classes:需要编译的类,用于注解处理
* Iterable 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;
}
}
}


推荐阅读
  • ElasticSearch 集群监控与优化
    本文详细介绍了如何有效地监控 ElasticSearch 集群,涵盖了关键性能指标、集群健康状况、统计信息以及内存和垃圾回收的监控方法。 ... [详细]
  • java文本编辑器,java文本编辑器设计思路
    java文本编辑器,java文本编辑器设计思路 ... [详细]
  • 深入理解Vue.js:从入门到精通
    本文详细介绍了Vue.js的基础知识、安装方法、核心概念及实战案例,帮助开发者全面掌握这一流行的前端框架。 ... [详细]
  • 本文总结了优化代码可读性的核心原则与技巧,通过合理的变量命名、函数和对象的结构化组织,以及遵循一致性等方法,帮助开发者编写更易读、维护性更高的代码。 ... [详细]
  • 深入解析Java虚拟机(JVM)架构与原理
    本文旨在为读者提供对Java虚拟机(JVM)的全面理解,涵盖其主要组成部分、工作原理及其在不同平台上的实现。通过详细探讨JVM的结构和内部机制,帮助开发者更好地掌握Java编程的核心技术。 ... [详细]
  • 深入解析 Android IPC 中的 Messenger 机制
    本文详细介绍了 Android 中基于消息传递的进程间通信(IPC)机制——Messenger。通过实例和源码分析,帮助开发者更好地理解和使用这一高效的通信工具。 ... [详细]
  • 本文探讨了在 SQL Server 中使用 JDBC 插入数据时遇到的问题。通过详细分析代码和数据库配置,提供了解决方案并解释了潜在的原因。 ... [详细]
  • Java多重继承的替代方案及设计考量
    本文探讨了Java为何不支持多重继承,并深入分析了其背后的原理和替代方案。通过理解Java的设计哲学,开发者可以更好地利用接口和其他特性来实现复杂的类结构。 ... [详细]
  • 本文深入探讨了UNIX/Linux系统中的进程间通信(IPC)机制,包括消息传递、同步和共享内存等。详细介绍了管道(Pipe)、有名管道(FIFO)、Posix和System V消息队列、互斥锁与条件变量、读写锁、信号量以及共享内存的使用方法和应用场景。 ... [详细]
  • 云屏系统基于嵌入式微系统msOS,旨在解决当前嵌入式彩屏GUI编程中硬件要求高、软件开发复杂、界面效果不佳等问题。该系统通过结合MCU和Android技术,利用Html5+JavaScript实现高效、易用的图形用户界面开发,使嵌入式开发人员能够专注于业务逻辑。 ... [详细]
  • 本文详细介绍了如何正确配置Java环境变量PATH,以确保JDK安装完成后能够正常运行。文章不仅涵盖了基本的环境变量设置步骤,还提供了针对不同操作系统下的具体操作指南。 ... [详细]
  • 洞态IAST Java Agent 实现AOP技术详解
    本文深入探讨了洞态IAST Java Agent如何通过AOP技术实现方法调用链和污点值传播等功能,为读者提供了详细的源码分析。 ... [详细]
  • 本文详细介绍了Java中的注解功能,包括如何定义注解类型、设置注解的应用范围及生命周期,并通过具体示例展示了如何利用反射机制访问注解信息。 ... [详细]
  • 为了提高应用系统的稳定性和用户体验,构建一个既高效又合理的异常处理框架至关重要。本文探讨了如何设计这样一个框架,确保系统能够优雅地处理所有运行时异常,并向用户提供友好的反馈。 ... [详细]
  • 字节跳动夏季招聘面试经验分享
    本文详细记录了字节跳动夏季招聘的面试经历,涵盖了一、二、三轮面试的技术问题及项目讨论,旨在为准备类似面试的求职者提供参考。 ... [详细]
author-avatar
晒太阳的人2015
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有