交互式解释器环境
Read(取值)-> Evaluation(求值)-> Print(打印)-> Loop(循环)
python,scala都提供原生的REPL ,例如在scala命令行内,键入scala代码,会直接返回结果
既可以作为一个独立的程序运行,也可以包含在其他程序中作为整体程序的一部分使用
当前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文档
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代码
为了“解释”一行代码,编译器将生成一个新对象,其中包含代码,和公共成员(以导出由该代码定义的所有变量)
要提取解释的结果显示给用户,将创建第二个“结果对象”,导入由上述对象导出的变量,然后导出名为“ eval”和“ print”的成员
优缺点
主要的优点是解释代码的行为与编译代码完全一样,包括全速运行
主要的缺点是重新定义类和方法不能正确处理,因为在Java级别的重新绑定在技术上是困难的
从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文档
重点在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 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;
}
}
在pom文件中引入插件,其实3.1版本即可
<properties>
<maven-compiler-plugin.version>3.6.1maven-compiler-plugin.version>
properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.pluginsgroupId>
<artifactId>maven-compiler-pluginartifactId>
<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