我有一个很奇怪的问题。我做了一些非常疯狂的事情:我使用IKVM将使用sbt-assembly插件组装的hadoop库的胖uber-jar转换为dll。我写了一个小的测试程序,将其归结为以下内容:
var u = new java.net.URI("hdfs://my-namenode:8020/");
var fs = org.apache.hadoop.fs.FileSystem.get(u, new org.apache.hadoop.conf.Configuration());
foreach(var s in fs.listStatus(new org.apache.hadoop.fs.Path("/"))) {
Console.WriteLine(s.getPath().toString());
}
当我在控制台应用程序中使用hadoop.dll和必需的IKVM dll作为引用添加运行此命令时,它将列出我的HDFS的内容。
但是,当我将这段代码完全包装在DLL中时,将SAME依赖项添加到该DLL中,并从我的控制台应用程序中调用它,我得到:
No FileSystem for scheme: hdfs
当通过fs.hdfs.impl
密钥在Hadoop conf中指定正确的类名称时,我得到一个ClassNotFoundException
。
可执行文件与DLL中的依赖关系解析是否不同,或者它是IKVM特定的行为?
编辑:另一个奇怪的行为:当我FileSystem
在控制台应用程序中构造一次,然后在DLL中调用该方法时,它将运行。
我自己找到了答案(再次...)
它不必执行.net如何处理依赖项加载,但是IKVM(以及Java)如何处理类的动态加载就可以了。
我翻阅了Hadoop源代码,发现了以下内容:
private ClassLoader classLoader;
{
classLoader = Thread.currentThread().getContextClassLoader();
if (classLoader == null) {
classLoader = Configuration.class.getClassLoader();
}
}
这条线classLoader = Thread.currentThread().getContextClassLoader();
在这里特别有趣。我的控制台应用程序的上下文类加载器是它的上下文-没有提到任何Hadoop的类,因此ClassNotFoundException
当明确设置fs.hdfs.impl
到org.apache.hadoop.hdfs.DistributedFileSystem
。
幸运的是,Configuration
该类具有一个method setClassLoader
,因此在构造配置时执行以下操作:
var conf = new org.apache.hadoop.conf.Configuration();
conf.setClassLoader(conf.getClass().getClassLoader());
conf.set("fs.hdfs.impl", "org.apache.hadoop.hdfs.DistributedFileSystem");
有用!这是因为conf.getClass().getClassLoader()
返回conf
上下文的类加载器-即,hadoop.dll
具有类的转换后的uber-jar。
尽管仍然需要显式声明文件系统类,fs.XXXX.impl
因为自动文件系统解析机制如下所示:
private static void loadFileSystems() {
synchronized (FileSystem.class) {
if (!FILE_SYSTEMS_LOADED) {
ServiceLoader<FileSystem> serviceLoader = ServiceLoader.load(FileSystem.class);
for (FileSystem fs : serviceLoader) {
SERVICE_FILE_SYSTEMS.put(fs.getScheme(), fs.getClass());
}
FILE_SYSTEMS_LOADED = true;
}
}
如您所见,文件系统在这里解析:
ServiceLoader<FileSystem> serviceLoader = ServiceLoader.load(FileSystem.class);
此方法Thread.currentThread().getContextClassLoader()
再次使用,这意味着我的控制台应用程序没有hadoop类。
因此,tl; dr:创建之后Configuration
,将其ClassLoader手动设置为dll的上下文类加载器。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句