Zeppelin源码分析-独立解释器 JVM 相关分析(3)

InterpreterContext 类

InterpreterContext 类可以说是一个 ParaGraph 运行时的上下文。在一个 ParaGraph 运行时,主进程 JVM 和 解释器 JVM 都会这个类的对象。
+ 这个类中有一些属性 noteId、replName、paragraphId 等属性是运行时候的一些基本信息。
+ 其中 out 属性就是专门负责流的写入,这在流相关分析中已经说明,故不再赘述。
+ 其中还有一个属性 client,类型为 RemoteEventClientWrapper ,它只有一个实现类 RemoteEventClient ,因此实际运行类型其实就是 RemoteEventClient,它可以看成是对 RemoteInterpreterEventClient 的缩减,只提供了 RemoteInterpreterEventClient 中的一种方法:onMetaInfosReceived 方法,这个方法目前只在 SparkInterpreter 中的 populateSparkWebUrl 方法中被调用过。
+ 这个类还有一个 ThreadLocal\

InterpreterContextRunner 类

这个类是一个抽象类,只有两个字段,并且是一个进程类,它的是为在一个 ParaGraph 中运行其他 ParaGraph 而服务的:

String noteId;
private String paragraphId;

它的子类如下:

Paragraph.ParagraphRunner 类

由于这个类在 Paragraph 中被定义,因此运行在主进程中,下面是类的定义,但是这个实现类的 Note 属性和 run 方法其实没什么用,下面会说明原因。

static class ParagraphRunner extends InterpreterContextRunner {
  private transient Note note;
  public ParagraphRunner(Note note, String noteId, String paragraphId) {
    super(noteId, paragraphId);
    this.note = note;
  }
  @Override
  public void run() {
    note.run(getParagraphId());
  }
}

在运行一个 ParaGraph 时会调用 getInterpreterContext 方法,这个方法中会将该 ParaGraph 所在的 Note 中所有的 ParaGraph 封装成一个 List\

for (Paragraph p : note.getParagraphs()) {
  runners.add(new ParagraphRunner(note, note.getId(), p.getId()));
}

然后在 RemoteInterpreter 调用 interpret 方法时,主进程中的 InterpreterContext 对象会转化成 RemoteInterpreterContext 再作为参数传入 interpret 方法,然后通过 Thirft 协议传送到 Server 端之后, Server 端又会将 RemoteInterpreterContext 重新转化为 InterpreterContext 对象,从代码中也可以看到,Note 属性和 run 方法其实没什么用。
RemoteInterpreter 调用 interpret 方法:

RemoteInterpreterResult remoteResult = client.interpret(
    sessionKey, className, st, convert(context));

RemoteInterpreter 类中 InterpreterContext 对象转化成 RemoteInterpreterContext

private RemoteInterpreterContext convert(InterpreterContext ic) {
  return new RemoteInterpreterContext(ic.getNoteId(), ic.getParagraphId(), ic.getReplName(),
      ic.getParagraphTitle(), ic.getParagraphText(), gson.toJson(ic.getAuthenticationInfo()),
      gson.toJson(ic.getConfig()), gson.toJson(ic.getGui()), gson.toJson(ic.getRunners()));
}

RemoteInterpreterServer 类中 RemoteInterpreterContext 对象又转回 InterpreterContext

private InterpreterContext convert(RemoteInterpreterContext ric, InterpreterOutput output) {
  List<InterpreterContextRunner> contextRunners = new LinkedList<>();
  List<InterpreterContextRunner> runners = gson.fromJson(ric.getRunners(),
          new TypeToken<List<RemoteInterpreterContextRunner>>() {
      }.getType());
  for (InterpreterContextRunner r : runners) {
    contextRunners.add(new ParagraphRunner(this, r.getNoteId(), r.getParagraphId()));
  }
  return new InterpreterContext(
      ric.getNoteId(),
      ric.getParagraphId(),
      ric.getReplName(),
      ric.getParagraphTitle(),
      ric.getParagraphText(),
      gson.fromJson(ric.getAuthenticationInfo(), AuthenticationInfo.class),
      (Map<String, Object>) gson.fromJson(ric.getConfig(),
          new TypeToken<Map<String, Object>>() {}.getType()),
      gson.fromJson(ric.getGui(), GUI.class),
      interpreterGroup.getAngularObjectRegistry(),
      interpreterGroup.getResourcePool(),
      contextRunners, output, remoteWorksController, eventClient);
}

RemoteInterpreterServer.ParagraphRunner 类

这个类在 RemoteInterpreterServer 被定义。这个类中的 run 方法和 server 属性才是真正有用的,因为需要开启这个线程向 Event 队列发送消息,使得主进程主动新建并提交需要运行的 ParaGraph 对应的 job。

static class ParagraphRunner extends InterpreterContextRunner {
  Logger logger = LoggerFactory.getLogger(ParagraphRunner.class);
  private transient RemoteInterpreterServer server;
  public ParagraphRunner(RemoteInterpreterServer server, String noteId, String paragraphId) {
    super(noteId, paragraphId);
    this.server = server;
  }
  @Override
  public void run() {
    server.eventClient.run(this);
  }
}

ZeppelinContext 类

这个类是一个比较神奇的类,但是看源码也不难发现其中奥秘。SparkInterpreter 中有一个属性名就叫 z,这个属性的类型就是 ZeppelinContext 类,在 open 函数中会对新建一个这个类的对象并使 z 引用之,所以当你使用 z.XXX() 时,其实就是调用 z 引用的 ZeppelinContext 类的对象的方法,然后进行处理,处理之后将结果返回或者用流返回或者向该 JVM 的消息队列中发送一个 Event 。下面拿几个常用方法来说明该类是如何工作的。

showDF 方法

它有两个重载的方法,一个是两个参数的,就是我们在网页中调用的方法,另一个是四个参数的( SparkSqlInterpret 的 interpret 方法调用的就是这个方法),其中两个参数的方法最终调用的也是四个参数的方法,因此这里只说一下四个参数的方法。四个参数的方法根据传入的 df 运用反射调用了 queryExecution , analyzed 和 output 方法得到最终要写的数据 columns,然后之后就是根据这个数据按照指定格式转换成字符串,并在字符串的开头加上 %table 表明返回类型是 Table 类型,然后前台 js 接到之后处理就会呈现我们看到的图表。四个参数的方法关键代码如下:

Object qe = df.getClass().getMethod("queryExecution").invoke(df);
Object a = qe.getClass().getMethod("analyzed").invoke(qe);
scala.collection.Seq seq = (scala.collection.Seq) a.getClass().getMethod("output").invoke(a);
columns = (List<Attribute>)scala.collection.JavaConverters.seqAsJavaListConverter(seq)
                                                          .asJava();

show 方法

这个方法其实最终调用的还是 showDF 方法,因此不在赘述。

run 方法

select 方法

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值