Zeppelin 使用JShell实现java解释器,从此用notebook写java
来源:互联网 发布:ubuntu软件源不能更新 编辑:程序博客网 时间:2024/05/21 05:59
REPL
交互式解释器环境
Read(取值)-> Evaluation(求值)-> Print(打印)-> Loop(循环)
python,scala都提供原生的REPL ,例如在scala命令行内,键入scala代码,会直接返回结果
既可以作为一个独立的程序运行,也可以包含在其他程序中作为整体程序的一部分使用
Zeppelin0.7.2目前不支持java的原因
当前spark解释器只支持scala,虽然提供了javaSparkContext的一个实例jsc,但并没有为它提供初始化,
我对spark解释器的源码进行了阅读,通过调用scala的REPL执行scala代码
scala调用REPL的关键代码:使用反射,将代码扔到repl中执行
/** * intp - org.apache.spark.repl.SparkIMain (scala 2.10) * intp - scala.tools.nsc.interpreter.IMain; (scala 2.11) */private Results.Result interpret(String line) { return (Results.Result) Utils.invokeMethod( intp, "interpret", new Class[] {String.class},//方法的参数列表 new Object[] {line});//方法执行时要用的实参}
代码的执行结果直接通过控制台输出,在这之前做了输出重定向,所以直接重定向到InterpreterOutputStream输出(提供了write方法,以字节数组的形式输出)。并不做拦截或返回,这也是为什么dataset.show的输出没有直接提供Zeppelin强大的可视化功能,不过提供了其他解决办法:zeppelincontext类封装了各种输出形式的实现,包括input,chexkbox等表单,show方法封装了dataframe的可视化图表形式输出等,如果想让dataset拥有和select语句在Zeppelin中一样强大的可视化效果,自己调用z.show方法即可
Scala REPL
scala REPL文档
http://docs.scala-lang.org/overviews/repl/overview.html
IMain
http://www.scala-lang.org/api/2.12.1/scala-compiler/scala/tools/nsc/interpreter/IMain.html
scala代码解释器
compile()加载一个完整的Scala文件
interpret()根据用户的请求执行一行Scala代码
bind()将对象绑定到一个变量,然后可以被稍后解释的代码使用
整体方法基于:编译所请求的代码,然后使用Java类加载器和Java反射来运行代码并访问其结果
细节:一个单独的编译器实例用于累积所有成功编译或解释的Scala代码
为了“解释”一行代码,编译器将生成一个新对象,其中包含代码,和公共成员(以导出由该代码定义的所有变量)
要提取解释的结果显示给用户,将创建第二个“结果对象”,导入由上述对象导出的变量,然后导出名为“
优缺点
主要的优点是解释代码的行为与编译代码完全一样,包括全速运行
主要的缺点是重新定义类和方法不能正确处理,因为在Java级别的重新绑定在技术上是困难的
JShell
从Java9开始,java也可以原生支持repl,这就是JShell
目前java9还未正式发布,不过功能已经相对完善,可以在这里下载与体验http://blog.csdn.net/nougats/article/details/76219357
可以直接在bin目录下启动JShell,体验强大功能
JShell为我们提供了良好API,可以实现我们自己的解释器
http://download.java.net/java/jdk9/docs/api/jdk/jshell/package-summary.html
简单概括:把代码丢进JShell里,JShell会生成一系列snippet流,每一个snippet都有自己的状态标记,eval方法会执行一句代码,并返回该snippet的状态和初始化的变量值等信息,实际功能十分强大,还需自己看API文档
为Zeppelin0.7.2实现java解释器
重点在open,interpret方法,关键点有输出重定向,代码完整判断,source,remaining的使用
public class JavaInterpreter extends Interpreter { public static Logger logger = LoggerFactory.getLogger(JavaInterpreter.class); private JShell j; private InterpreterOutputStream outputStream;//zeppelin的输出流,目的是重定向JShell向控制台输出为向web页面输出 public JavaInterpreter(Properties property) { super(property); } public void open() { //输出重定向第一步,JShell中System.out这类输出会默认输出到控制台,在zeppelin上显示不出,需要重定向JShell输出到zeppelin的输出流 outputStream = new InterpreterOutputStream(logger); PrintStream ps = new PrintStream(outputStream); //此处out为更改JShell输出流,err为更改错误信息输出流,但并没有得到想要的错误信息,问题暂未解决 j = JShell.builder().err(ps).out(ps).build(); } public void close() { } public InterpreterResult interpret(String input, InterpreterContext interpreterContext) { //这里真正结束了重定向,interpreterContext.out为当前段落的输出流,将outputStream流的输出定向为interpreterContext.out outputStream.setInterpreterOutput(interpreterContext.out); InterpreterResult.Code code = InterpreterResult.Code.SUCCESS; StringBuffer sb = new StringBuffer(); while (!input.isEmpty()) { SourceCodeAnalysis.CompletionInfo c = j.sourceCodeAnalysis().analyzeCompletion(input); //source返回代码的第一个Snippet,比如以第一个分号为界,eval一次只会执行一个Snippet List<SnippetEvent> events = j.eval(c.source()); for (SnippetEvent e : events) { sb.append(e.value() + "\n"); if (e.causeSnippet() == null) { if (e.status() == Snippet.Status.REJECTED) { try { //向输出流写出错误代码 interpreterContext.out.write("ERROR: " + c.source() + "\n"); code = InterpreterResult.Code.INCOMPLETE; } catch (IOException e1) { e1.printStackTrace(); } } } } //remaining返回代码除去source的剩余部分,执行eval后剩余的部分,也就是还未被执行的Snippet input = c.remaining(); } return new InterpreterResult(code); } public void cancel(InterpreterContext interpreterContext) { } public FormType getFormType() { return FormType.NATIVE; }//三种可选NATIVE,SIMPLE,NONE,具体差异并没有搞清楚,跟具体逻辑实现无关,普遍遇到过这里报错,但还没有搞清原因 public int getProgress(InterpreterContext interpreterContext) { return 0; }}
java9打包
在pom文件中引入插件,其实3.1版本即可
<properties><maven-compiler-plugin.version>3.6.1</maven-compiler-plugin.version> </properties>
<build> <plugins> <plugin><groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>${maven-compiler-plugin.version}</version> </plugin> </plugins> </build>
github上一些其他复杂的手段,使用toolchains等,我并没有用上
https://muyinchen.github.io/2017/07/19/%E5%A6%82%E4%BD%95%E5%9C%A8Maven%E9%A1%B9%E7%9B%AE%E4%B8%AD%E8%AE%BE%E7%BD%AEJava%209/
https://github.com/cfdobber/maven-java9-jigsaw
https://cwiki.apache.org/confluence/display/MAVEN/Java+9+-+Jigsaw
- Zeppelin 使用JShell实现java解释器,从此用notebook写java
- 用java写一个Brainfuck解释器
- NoteBook Java实现记事本功能
- 使用Java写的解释器(一)
- Java SE 9(JDK9)环境安装及交互式编程环境Jshell使用示例
- Java SE 9(JDK9)环境安装及交互式编程环境Jshell使用示例
- Java SE 9(JDK9)环境安装及交互式编程环境Jshell使用示例
- 使用antlr4及java实现snl语言的解释器
- Apache Zeppelin 中 Spark 解释器
- Apache Zeppelin 中 JDBC通用 解释器
- Apache Zeppelin 中 Hive 解释器
- Apache Zeppelin 中 HDFS文件系统 解释器
- Apache Zeppelin 中 Elasticsearch 解释器
- Apache Zeppelin 中 Flink 解释器
- Apache Zeppelin 中 R 解释器
- Apache Zeppelin 中 Alluxio 解释器
- Apache Zeppelin 中 Cassandra CQL 解释器
- Zeppelin 自定义Kafka解释器Interpreter开发
- linux驱动中锁的使用
- iOS 打包ipa如何瘦身
- CentOS7.3使用BIND配置DNS服务器(一)
- su incorrect password问题 su无法切换用户问题 以及权限s、t、i、a补充
- ConcurrentHashMap实现原理及源码分析
- Zeppelin 使用JShell实现java解释器,从此用notebook写java
- 基于12槽PCIe扩展坞支持11块PCIE SSD硬盘的了解
- 组合模式
- FlexPaper+SWFTools ,java实现在线文档浏览
- Caffe-Miscoroft无训练日志解决方法
- Android shape drawable XML 可绘制图形的创建与使用
- ViewPager初识(二)
- 嵌入式Linux下各种文件系统名词解析
- redis 简单使用总结