和 Interpreter 直接相关类有以下几个:
Interpreter, InterpreterFactory, RemoteInterpreter, InterpreterGroup, InterpreterSetting。
由于篇幅有限,这里分开介绍。
Interpreter 类及其子类
Interpreter 是一个接口,所有的子类如下(只列举出 SparkInterpreter ):
其中除了 SparkInterpreter 等具体的完成解释功能的类,其余的实现类全部运行在主进程中。
RomoteInterpreter
RomoteInterpreter 类是 SparkInterpreter 等具体的完成解释功能的类的本地代理,其实就可以看成 Thrif 协议的客户端,但是其实这个对象并没有直接持有 Client 类对象的引用,而是在使用 Client 类的时候,用 RemoteInterpreterProcess 对象的方法获得,这在解释器工厂类的 createInterpretersForNote 会详细介绍。
然后比较坑的就是官方那张图:
之前一直以为Thrift 的 Server只有一个,但其实程序跑起来之后实际其实应该是这样:
图中的 RemoteInterpreterServer 类是一个线程,并实现了 RemoteInterpreterService.Iface 类,表明这是 Thrif 协议的服务器端( Thrift 协议简单来说就是:有一个 Client 和 Server ,两个运行在不同的 JVM,Server 对外开放指定端口,Client 可以通过服务器开放的端口来调用服务器相应的方法,相应方法在 XXX.thrift 文件中定义,然后可以直接使用 Thirft 官方提供的工具和 XXX.thrift 文件生成指定语言的代码,然后使用时只需要遵循规范实现一些类即可),RemoteInterpreterServer 类中通过反射的方法将具体的解释器进程启动,它和具体的解释器在同一个 JVM 线程中,启动代码如下:
Class<Interpreter> replClass = (Class<Interpreter>) Object.class.forName(className);
Properties p = new Properties();
p.putAll(properties);
setSystemProperty(p);
Constructor<Interpreter> constructor =
replClass.getConstructor(new Class[] {Properties.class});
Interpreter repl = constructor.newInstance(p);
repl.setClassloaderUrls(new URL[]{});
RomoteInterpreter 类和 RemoteInterpreterServer 类是直接交互的类(依靠 Thrift 协议),当在主进程中调用 RomoteInterpreter 类的 Client 对象的方法时,其实会调用 RemoteInterpreterServer 类的同名的方法,RomoteInterpreter 类存有 RemoteInterpreterProcess 的对象(之后的文件会说这个类),通过这个对象可以获取到 Thrift 的 Client 对象。
SparkInterpreter 等具体实现类
这些类是真正干活的类,前面说过和 RomoteInterpreter 类直接交互的是 RemoteInterpreterServer 类,在 Thrift 客户端调用服务器相应的方法时,服务器端会调用具体的解释器的相应方法,比如 RemoteInterpreterServer 类的 interpret代码如下:(虽然封装成了 Job,但是最终还是调用了 SparkInterpreter 等具体实现类的 interpret 方法,这个调度问题在之后会说):
@Override
public RemoteInterpreterResult interpret(String noteId, String className, String st,
RemoteInterpreterContext interpreterContext) throws TException {
// 省略
Interpreter intp = getInterpreter(noteId, className);
InterpretJob job = new InterpretJob(
interpreterContext.getParagraphId(),
"remoteInterpretJob_" + System.currentTimeMillis(),
jobListener,
JobProgressPoller.DEFAULT_INTERVAL_MSEC,
intp,
st,
context);
}
// 省略
}
ClassLoaderInterpreter 和 LazyOpenInterpreter
WrappedInterpreter 是一个接口,作用其实就是包装 Interpreter 的实现类,他有两个实现类:ClassLoaderInterpreter 和 LazyOpenInterpreter,该接口的定义如下:
public interface WrappedInterpreter {
public Interpreter getInnerInterpreter();
}
ClassLoaderInterpreter 其实就是运行在主进程的具体解释器的封装,但是由于目前所有的具体解释器都运行在独立的 JVM 中,因此这个类其实没有什么作用,该类在 InterpreterFactor 被构造,关键代码如下:
// InterpreterFactor 中该类被构造
Class<Interpreter> replClass = (Class<Interpreter>) cl.loadClass(className);
Constructor<Interpreter> constructor =
replClass.getConstructor(new Class[]{Properties.class});
Interpreter repl = constructor.newInstance(property);
repl.setClassloaderUrls(ccl.getURLs());
LazyOpenInterpreter intp = new LazyOpenInterpreter(new ClassloaderInterpreter(repl, cl));
// InterpreterFactor 类字段
private ClassLoader cl;
private Interpreter intp;
LazyOpenInterpreter 正如其名,其实是对 RomoteInterpreter 的简单封装,存在的意义就是可以延后启动,字段如下:
private Interpreter intp;
volatile boolean opened = false;