我们知道Datax是基于框架+插件方式进行开发的。
之前我们也了解了怎么开发一个简单的插件。那这些插件是怎么被加载和使用的?
源码查看
- com.alibaba.datax.core.job.JobContainer
进入start()方法的this.init()方法
进入this.jobReader = this.initJobReader(jobPluginCollector);
private Reader.Job initJobReader(
JobPluginCollector jobPluginCollector) {
this.readerPluginName = this.configuration.getString(
CoreConstant.DATAX_JOB_CONTENT_READER_NAME);
classLoaderSwapper.setCurrentThreadClassLoader(LoadUtil.getJarLoader(
PluginType.READER, this.readerPluginName));
Reader.Job jobReader = (Reader.Job) LoadUtil.loadJobPlugin(
PluginType.READER, this.readerPluginName);
jobReader.setPluginJobConf(this.configuration.getConfiguration(
CoreConstant.DATAX_JOB_CONTENT_READER_PARAMETER));
jobReader.setPeerPluginJobConf(this.configuration.getConfiguration(
CoreConstant.DATAX_JOB_CONTENT_WRITER_PARAMETER));
jobReader.setJobPluginCollector(jobPluginCollector);
jobReader.init();
classLoaderSwapper.restoreCurrentThreadClassLoader();
return jobReader;
}
上面代码主要做了:
通过配置文件获取插件的名称
保存当前classLoader,并将当前线程的classLoader设置为所给classLoader
加载Reader 插件的实现类
初始化Reader的参数
执行Reader job的init方法
将当前线程的类加载器设置为保存的类加载,恢复
public static AbstractJobPlugin loadJobPlugin(PluginType pluginType,
String pluginName) {
Class<? extends AbstractPlugin> clazz = LoadUtil.loadPluginClass(
pluginType, pluginName, ContainerType.Job);
try {
AbstractJobPlugin jobPlugin = (AbstractJobPlugin) clazz
.newInstance();
jobPlugin.setPluginConf(getPluginConf(pluginType, pluginName));
return jobPlugin;
} catch (Exception e) {
throw DataXException.asDataXException(
FrameworkErrorCode.RUNTIME_ERROR,
String.format("DataX找到plugin[%s]的Job配置.",
pluginName), e);
}
}
通过LoadUtil.loadPluginClass(
pluginType, pluginName, ContainerType.Job) 方法加载到我们需要的class,然后通过反射进行实例化。
private static synchronized Class<? extends AbstractPlugin> loadPluginClass(
PluginType pluginType, String pluginName,
ContainerType pluginRunType) {
Configuration pluginConf = getPluginConf(pluginType, pluginName);
JarLoader jarLoader = LoadUtil.getJarLoader(pluginType, pluginName);
try {
return (Class<? extends AbstractPlugin>) jarLoader
.loadClass(pluginConf.getString("class") + "$"
+ pluginRunType.value());
} catch (Exception e) {
throw DataXException.asDataXException(FrameworkErrorCode.RUNTIME_ERROR, e);
}
}
这里获取到JarLoader(继承子URLClassLoader)
通过JarLoader的loadClass方法加载我们plugin.json配置的class
- 获取ClassLoader方法 getJarLoader
public static synchronized JarLoader getJarLoader(PluginType pluginType,
String pluginName) {
Configuration pluginConf = getPluginConf(pluginType, pluginName);
JarLoader jarLoader = jarLoaderCenter.get(generatePluginKey(pluginType,
pluginName));
if (null == jarLoader) {
String pluginPath = pluginConf.getString("path");
if (StringUtils.isBlank(pluginPath)) {
throw DataXException.asDataXException(
FrameworkErrorCode.RUNTIME_ERROR,
String.format(
"%s插件[%s]路径非法!",
pluginType, pluginName));
}
jarLoader = new JarLoader(new String[]{pluginPath});
jarLoaderCenter.put(generatePluginKey(pluginType, pluginName),
jarLoader);
}
return jarLoader;
}
此方法流程:
根据类型和名称从缓存中获取
如果没有则去创建,首先获取插件的路径.比如:"path": "D:\\app\\workspace\\idea\\DataX\\target\\datax\\datax\\plugin\\reader\\mysqlreader"
然后根据JarLoader里面的getURLs(paths)获取插件路径下所有的jar包。
创建单独的URLClassLoader。
把创建的ClassLoader缓存起来,后续就不用重新创建ClassLoader,返回。
- com.alibaba.datax.core.util.container.JarLoader
com.alibaba.datax.core.util.container.JarLoader
此类:提供Jar隔离的加载机制,会把传入的路径、及其子路径、以及路径中的jar文件加入到class path
这里就不展示代码了。
reader job加载完之后,reader task
writer job ,writer task都是一样的流程,快去查看一下吧。
打开App,阅读手记