我预计可以使用myModuleA中的Guava-19和myModuleB中的guava-20,因为拼图模块有自己的类路径。
让我们说myModuleA使用Iterators.emptyIterator(); - 在guava-20中删除,myModuleB使用新的静态方法FluentIterable.of(); - 番石榴19中没有。不幸的是,我的测试是否定的。在编译时,它看起来很好。与运行时相反,结果是NoSuchMethodError。意味着,类加载器中第一个类决定哪个类失败。
与底层耦合的封装?我找到了自己的理由。由于传递依赖性会产生与以前相同的问题,因此无法支持它。如果在ModuleA和ModuleB中的签名中发生版本冲突的guava类依赖于它。应该使用哪个类?
但为什么我们可以通过互联网阅读"拼图 - 模块系统停止了类路径地狱"?我们现在有多个较小的"类似的路径"有同样的问题。这不仅仅是一个问题,而是一个不确定性。
答案 0 :(得分:12)
首先进行修正:你说模块有自己的类路径,这是不正确的。应用程序的类路径保持不变。与之并行的是模块路径,但它基本上以相同的方式工作。特别是,所有应用程序类都由相同的类加载器加载(默认情况下至少)。
对于所有应用程序类,只有一个类加载器也解释了为什么不能存在同一类的两个版本:整个类加载基础结构是基于完全限定类名称足以满足的假设。用类加载器识别一个类。
这也为多个版本打开了解决方案的路径。就像之前你可以通过使用不同的类加载器来实现它。模块系统本机的方法是创建额外的layers(每个层都有自己的加载器)。
模块系统是否用module hell替换类路径地狱?好吧,如果不创建新的类加载器,仍然无法使用同一个库的多个版本,因此这个基本问题仍然存在。
另一方面,由于split packages,您现在至少在编译或启动时遇到错误。这可以防止程序巧妙地行为不端,这也不是那么糟糕。
答案 1 :(得分:4)
理论上,可以在应用程序中使用不同版本的相同库。实现这一目标的概念:分层!
当您学习Jigsaw under the hood时,您会找到专门讨论此主题的整个部分。
基本上,您可以使用这些图层进一步分组模块。图层是在运行时构建的;他们有自己的类加载器。含义:应该绝对可以在一个应用程序中使用不同版本的模块 - 它们只需要进入不同的层。如图所示 - 这种“多版本支持”由java / jigsaw工作人员积极讨论。它不是一个不起眼的功能 - 意味着在一个引擎盖下支持不同的模块版本。
此时唯一的免责声明:遗憾的是,没有“完整的”源代码示例(我知道),因此我只能链接到该Oracle演示文稿。
换句话说:对于这个版本问题,有一些类型的解决方案 - 但是要用这个新想法在现实世界代码中体验,需要更多的时间。确切地说:不同的类加载器可以使用不同的隔离层。有没有支持,允许您“同一个对象”同时使用modV1和modV2。你只能有两个对象,一个使用modV1,另一个使用modV2。
(德国读者可能希望看一下here - 该出版物包含对图层主题的另一个介绍。)
答案 2 :(得分:1)
Java 9无法解决此类问题。简而言之,在Java 9中所做的是将经典访问修饰符(public,protected,package-private,private)扩展到jar级别。
在java 9之前,如果模块A依赖于模块B,则B中的所有公共类都将在A中可见。
使用Java 9,可以配置可见性,因此它可以仅限于类的子集,每个模块可以定义哪些包导出以及哪些包需要。
大多数检查都是由编译器完成的。
从运行时### BEGIN .ebextensions/logs.config
option_settings:
- namespace: aws:elasticbeanstalk:cloudwatch:logs
option_name: StreamLogs
value: true
- namespace: aws:elasticbeanstalk:cloudwatch:logs
option_name: DeleteOnTerminate
value: false
- namespace: aws:elasticbeanstalk:cloudwatch:logs
option_name: RetentionInDays
value: 7
files:
"/etc/awslogs/config/stdout.conf":
mode: "000755"
owner: root
group: root
content: |
[docker-stdout]
log_group_name=/aws/elasticbeanstalk/environment_name/docker-stdout
log_stream_name={instance_id}
file=/var/log/eb-docker/containers/eb-current-app/*-stdouterr.log
commands:
"00_restart_awslogs":
command: service awslogs restart
### END .ebextensions/logs.config
开始,没有大的变化,所有应用程序模块都由同一个类加载器加载,因此除非使用模块化,否则不可能在同一个jvm中使用不同版本的相同类像OSGI这样的框架或者自己操纵类加载器。
答案 3 :(得分:0)
正如其他人所暗示的那样,JPMS层可以提供帮助。您可以手动使用它们,但是Layrry可能对您有所帮助,这是一个流畅的API和基于配置的启动器,用于运行分层应用程序。它允许您通过配置定义层结构,并为您启动层图。它还支持在运行时动态添加/删除图层。
免责声明:我是Layrry的最初创建者