.net:DLL的依赖项加载与EXE的依赖加载不同吗?

拉贝延斯

我有一个很奇怪的问题。我做了一些非常疯狂的事情:我使用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.implorg.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] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

无法加载文件或程序集“ Oracle.ManagedDataAccessDTC.DLL”或其依赖项之一

可以禁止单个Composer依赖项从(自动)加载吗?

如果加载dll找不到依赖项,有什么方法可以捕获错误?

Webpack:从本地目录加载依赖项

设置依赖项的加载位置

npm-谁正在加载依赖项?

未加载Maven传递依赖项

从依赖项加载资源

加载.net包装程序无法加载本机依赖项

定制的ClassLoader可以加载忽略其依赖项的类吗?

加载可选的依赖项

如何加载Javascript及其依赖项?

无法通过Ajax加载Javascript依赖项

将DLL加载到其他AppDomain及其依赖项中

Requirejs:仅在需要时加载依赖项

加载项可以交流吗?连接加载项/加载项依赖性

如何使PostgreSQL加载依赖DLL的C模块?

注入依赖项会使加载更重吗?

Cytoscape。从URL加载依赖项

Open Alpr无法加载其依赖项

JSPM 未按预期加载依赖项

无法加载文件或程序集“video.player.net.dll”或其依赖项之一。找不到指定的模块。":"video.player.net.dll

使用 require 加载依赖项

Wordpress 入队样式依赖项无序加载

如何修复“无法加载共享库‘httpapi.dll’或其依赖项之一”

SelectPDF .Net Core 2.2:异常:转换失败。无法加载共享库“kernel32.dll”或其依赖项之一

延迟加载的模块共享相同的依赖项?

如何加载 Scala 依赖项?

如何修复 Azure 应用服务无法加载 DLL 'libwkhtmltox' 或其依赖项之一