另一个拼图观点

在过去的几周中,围绕即将发布的Java 9及其最著名的功能:Java平台模块系统JPMS展开了激烈的辩论。
–以项目拼图Jigsaw的名称而闻名。 模块系统以正式规范过程的形式引入Java生态系统
– JSR –需要由专家组以最终形式批准。 在该专家组的其他成员中,红帽和IBM的代表现已投票反对在他们认为尚未准备好生产的第一轮投票中拒绝Java的模块系统。

到底有什么毛病?

即使在今天,Java开发人员也对模块化非常熟悉。 像Maven这样的构建系统将代码组织为针对一组声明的依赖项进行编译的模块。 仅在运行时,这些模块才放到这些编译时模块边界消失的类路径上。 使用Jigsaw,模块路径可以作为此类路径的替代方式,JVM在运行时为其保留了此类编译时边界。 通过不使用此模块路径,应用程序应该像以前一样运行。 但是,这依赖于JVM内部的API的应用程序除外。 即使将类路径专门用于无法再访问内部Java API的情况下,Java标准库也始终作为模块的集合加载。

兼容性上的后一个限制引起了库和最终用户应用程序维护者的一些关注。 在这种情况下,最近的反对意见与这些关注关系不大可能会令人感到惊讶。 虽然提到兼容性方面的问题,但Red Hat和IBM都主要认为JPMS需要进一步扩展,以允许与现有模块系统(如JBoss模块和OSGi)更好地集成。

还有什么问题需要解决?

通过jar hell ,开发人员通常描述Java应用程序需要两个不同版本的库来满足不同的传递依赖关系的情况。 使用类路径,这是不可能的,因为一个版本的库会遮盖第二个副本。 如果是第一次加载给定名称的类,则系统类加载器将按其命令行顺序扫描jar文件,并加载其发现的第一个类文件。 在最坏的情况下,如果带阴影的jar文件包含一些链接到带阴影的jar类的专有类,则可能会导致科学怪人功能。 但是更典型的是,一旦触发了依赖于特定版本的功能,就会导致运行时失败。

使用OSGi和JBoss模块,可以部分解决此问题。 后一个模块系统允许每个库自己的类加载器加载一个库,从而避免了负责类路径的系统类加载器。 使用这种方法,可以通过隔离在单独的类加载器中来共存同一类的多个版本。 这样做,例如,两个库都可能都依赖于它们通常中断的Guava API的特定版本。 使用类加载器隔离,在加载依赖类时,任何库都会将调用委派给其所需的版本。

使用模块路径时,JPMS(当前)不应用此类类加载器隔离。 这意味着Java 9无法解决jar hell的问题。与使用类路径相反,JVM确实会检测到所描述的版本冲突并在启动时使应用程序失败,而不是推测意外的兼容性。 为了强制执行此约束,每个Java包名称现在都专有于特定模块或类路径。 因此,两个模块不可能共享一个包。 如果不打算公开私有软件包,则此限制也成立,这是Jigsaw评论家认为当前模块设计的另一个缺陷。

错过了逃脱地狱的机会吗?

为了使类加载器隔离有效,必须使同一模块的版本永不交互。 而且,尽管两个这样的版本当然永远不会直接交互,但是不幸的是,两个版本是不同模块的公共API的一部分比通常情况更常见。 例如,如果两个库返回番石榴的实例Function类型,每个模块的番石榴版本之间的版本冲突不能再使用的类加载器隔离,即使解决了Function型没有这些版本之间切换。 在运行时,任何已加载的类都被描述为其名称和类加载器的元组,但是由于两个类加载器现在提供了Function类型,应该解决哪个类型?

实际上,该描述的问题不能由模块系统解决。 相反,模块系统可以发现此冲突,并告知用户需要明确的解决方案。 这是通过JPMS的当前实现以及OSGi和JBoss模块实现的。 归根结底,只有通过以兼容方式发展API才能避免版本冲突。

拼图游戏太简单了吗?

尽管类装入器隔离模块系统仍然存在局限性,但当前反对Jigsaw的论点主要围绕此问题。 此外,拒绝Jigsaw的专家组成员指出,缺少对循环模块依赖关系的支持(“模块A依赖于B依赖于C依赖于A依赖”)以及在创建模块图后无法更改模块图。

从技术角度来看,当然可以添加这些功能。 实际上,Java 9已经附带了模块构建器API,该模块允许使用排他类加载器加载模块。 选择为模块路径保留单个类加载器没有技术限制。 相反,该决定被Oracle认为是JVM的负责任选择。 在深入探讨这些论点之前,我想声明我完全同意公司的推理。

类加载器隔离有什么问题?

如前所述,即使使用类加载器隔离,也常常无法避免手动版本管理。 此外,依赖具有不兼容版本(例如Guava)的通用API的库作者的确越来越掩盖了这种依赖性。 着色时,将库的代码复制到单独的名称空间中,从而使应用程序可以使用不同的名称而不是通过不同的类加载器来引用“其版本”。 当然,这种方法有其自身的缺陷,特别是当阴影依赖项使用JNI时。 另一方面,这种方法克服了在使用具有冲突的共享依赖项的库时,刚刚提到的类加载器隔离的缺点。 同样,通过隐藏公共依赖关系,库作者可以独立于部署方法而使用户免于潜在的冲突。

允许循环依赖既不会带来很大的技术挑战。 但是,循环依赖关系很少见,像Maven这样的许多构建系统都不支持它们。 通常,可以通过将至少一个模块分成实现和API来将循环依赖关系重构为非循环依赖关系。 在这种情况下,如果某个功能似乎很少引起人们的普遍关注,那么我认为角落情况并不能证明其附加功能是合理的,尤其是当类路径仍充当备用功能时。 而且,如果最终决定是错误的,则可以在以后的版本中始终启用循环依赖关系。 但是,取消此功能将是不可能的。

最后,动态模块提供的功能可能对多个应用程序有用。 根据我上一个项目的经验,当您需要动态地重新部署具有生命周期的模块时,OSGi是一个很好的选择。 也就是说,大多数应用程序都是静态的,没有充分的理由使用它。 但是,通过添加对动态模块图的支持,此功能的复杂性将转化为JPMS。 因此,我认为暂时不使用此功能,等到更好地理解其用途是正确的决定。 自然,可访问的模块系统会提高采用率。

兼容性至上

这种不兼容性是否意味着OSGi和JBoss模块的终结? 当然不是。 恰恰相反,标准化模块描述符的引入为现有模块系统提供了机会。 使用OSGi时,缺少描述包的清单标头是主要的痛点之一,因为大量库没有考虑专有模块描述符。 通过引入标准化的模块描述符,现有的模块系统可以通过使用后一个描述符作为模块描述的辅助来源来减轻此限制。

我毫不怀疑红帽和IBM出于最佳意图拒绝了JSR。 同时,我不能同意对模块系统缺乏覆盖面的批评。 在我看来,现有的变更对于Java生态系统的采用而言是充满挑战的,尤其是最后一刻引入类装入器隔离具有带来意外意外的潜力。 有鉴于此,我发现针对拼图的当前状态提出的论据不一致,因为它批评了向模块过渡的复杂性,但也要求对其进行扩展。

没有完善的模块系统

我个人认为,目前的JPMS提案面临两个重大挑战。 不幸的是,由于最近的讨论,它们成为了背景。

自动模块

如果没有模块描述符,则模块化代码只能以所谓的自动模块的形式引用非模块化jar文件。 自动模块没有任何限制,并由其jar文件命名。 这对于最终用户应用程序的开发人员非常有用,这些用户永远不会发布其代码以供其他应用程序使用。 但是,库开发人员确实缺少一个稳定的模块名称来引用其依赖的自动模块。 如果发布,它们将依赖稳定的文件名来获取依赖关系,这很难假设。

对于采用Jigsaw而言,这意味着一种自下而上的方法,其中任何库作者只能在所有相关代码都已经模块化之后才能对其软件进行模块化。 为了简化过渡,添加了一个清单条目,该清单条目允许发布具有稳定自动模块名称的jar,而无需模块化代码甚至迁移到Java9。这允许依赖此第一个库的其他用户使用具有稳定名称的库。对他们的代码进行模块化,从而突破了自下而上的要求。

我认为让库维护者在迁移其代码以完全使用JPMS之前声明一个明确的模块名称非常重要,并且我认为这是处理此问题的一种充分方法,这不可能提供更好的解决方案。

反思和可及性

使用Jigsaw,不再允许使用反射来访问非公共,未导出的成员,这是许多框架当前所认为的机会。 当然,设置了安全管理器后,即使在当今的Java版本中也无法进行这种访问,但是由于很少使用安全管理器,因此无需过多考虑。 对于Jigsaw,这种默认设置是相反的,在这种情况下,需要显式打开用于这种反射访问的包,从而影响许多Java应用程序。

总的来说,我认为Jigsaw的封装比当前的通用开放性更好。 如果我想让Hibernate访问我的bean,则JPMS允许我仅通过合格的出口将bean打开到Hibernate。 使用安全管理器,即使不是不可能实现,也很难控制这种细粒度的访问。 但是,这种过渡会带来很多麻烦,并且许多库的维护不够积极,无法适应这些新要求。 因此,添加此限制肯定会杀死某些原本可以提供价值的库。

此外,仍然存在一些反射的用例。 对于模拟库Mockito(我帮助维护),例如,我们需要一种在任何类加载器中定义类的方法。 这过去只能通过使用内部Java API来实现,而目前还没有其他选择。 由于Mockito仅在测试环境中使用,因此在这种情况下,安全性无需关注。 但是,由于sun.misc.Unsafe开放性,我们已经依靠该开放性来实例化模拟类而无需构造函数调用,因此我们可以通过使用其直接内存API更改其可访问性来简单地打开这些API。

当然,这在接下来的几年中还不够好解决,但是我坚信可以在完全删除不安全类之前解决这些问题。 作为一种可能性,可以使用需要在命令行上明确解决的测试模块来扩展JVM,并允许这种扩展访问。 另一种选择是要求任何测试运行程序都附加Java代理,因为它们具有突破模块障碍的能力。 但是就目前而言,任何维护的软件都有机会解决其非标准Java使用问题,并在未来几年继续讨论缺少的API。

寻找共识

考虑到社交焦虑的计算机呆子的刻板印象,软件开发可能是一件相当感性的事情。 甲骨文一直以来都是Java开发人员所讨厌的公司,当前的讨论在一定程度上推动了这一潮流。 但是,从Java作为一种语言和平台的成功来看,我确实认为Oracle值得称赞的是它在管理方面的客观出色表现。 考虑到未来的成功,当今破解软件是一项微妙而无济于事的任务。 任何重构正确但复杂的代码的人都应该同情这个挑战。

拼图项目经常因不必要的努力而受到批评,我承认这种想法已经超出了我的想法。 但是,归功于模块系统,像CORBA或RMI这样的自重组件最终可以从JVM中删除。 随着模块化Java应用程序大小的隐式减小,JVM对于在容器化应用程序和云计算中的使用变得越来越有吸引力,这对于Oracle的市场策略而言肯定不是巧合。 虽然当然可以将这种工作进一步推迟到更高的Java版本,但是JVM必须在某个时候解决功能的删除。 现在是一个好时机。

为了简化即将到来的过渡,将重大更改降低到最小很重要。 因此,我坚信扩展Jigsaw的范围并不符合更广泛的Java社区的最大利益。 最近投票的许多否决票都要求有关各方就悬而未决的问题达成共识。 不幸的是,在只有一方放弃立场的情况下才能达成共识的情况下,可以实施或放弃所讨论的功能。

考虑到典型的Java应用程序,我希望Oracle不会通过范围扩展来满足需求,只是为了确保对Jigsaw JSR进行成功的投票。 相反,我想呼吁那些对JSR表示反对的专家组成员重新考虑他们对整个Java生态系统需求的投票,因为现有企业模块解决方案的需求只是众多因素中的一个因素。 随着Java从商业应用程序到低延迟系统的广泛使用,自然而然地,不同的各方会为平台的发展确定不同的优先级。 我相信Oracle已经为服务于大多数用户的模块系统找到了共同点。

翻译自: https://www.javacodegeeks.com/2017/05/yet-another-jigsaw-opinion-piece.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/350787.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Cookie中不能有空格_前端小贴士 -- 全面了解Cookie

一、Cookie的出现浏览器和服务器之间的通信少不了HTTP协议,但是因为HTTP协议是无状态的,所以服务器并不知道上一次浏览器做了什么样的操作,这样严重阻碍了交互式Web应用程序的实现。针对上述的问题,网景公司的程序员创造了Cookie。…

线程面试题

1.在使用线程时,为什么不直接调用run()方法而是调用了start(): 直接调用run()方法,不存在线程的启动,属于调用实例方法,只有一条执行路径,不存在多线程并行交替执行了。调用start()方法属于启动线程,将自动…

Java IO - Reader

前言 JavaIO一共包括两种,一种是stream,一种是reader/writer,每种又包括in/out,所以一共是四种包。Java 流在处理上分为字符流和字节流。字符流处理的单元为 2 个字节的 Unicode 字符,分别操作字符、字符数组或字符串&…

python程序设计语言的执行方式_编程语言用Python执行程序的4种方式

在编写代码中,经常会遇到在 Python程序中打开外部程序的需求,那么在Python里如何打开外部程序呢?今天我们来介绍四种不同的方式,供大家参考收藏。 使用 os.system() os.system(command)是最简单的一种方式,我们import os模块&…

leetcode 994.腐烂的橘子

题目: 在给定的网格中,每个单元格可以有以下三个值之一: 值 0 代表空单元格;值 1 代表新鲜橘子;值 2 代表腐烂的橘子。每分钟,任何与腐烂的橘子(在 4 个正方向上)相邻的新鲜橘子都会…

运行时异常和检查性异常区别

Java提供了两类主要的异常:runtime exception和checked exception。checked 异常也就是我们经常遇到的IO异常,以及SQL异常都是这种异常。对于这种异常,JAVA编译器强制要求我们必需对出现的这些异常进行catch。所以,面对这种异常不管我们是否愿…

VS2015配置freegult

与vs配置opencv类似 1.首先先找到自己系统里OpenGL相关.h.lib .dll的位置 一般系统里已自带,只要去找到就好,我的位置: gl.h C:\Program Files\Microsoft SDKs\Windows\v6.0A\Include\gl OpenGL32.Lib GlU32.Lib C:\Program Files\Microsoft…

java 死锁的检测与修复_调查死锁–第4部分:修复代码

java 死锁的检测与修复在这个简短的博客系列的最后BadTransferOperation中,我一直在讨论分析死锁,我将修复BadTransferOperation代码。 如果您已经看过本系列的其他博客 ,那么您会知道,为了达到这一点,我创建了死锁演示…

python下载url_三种Python下载url并保存文件的代码详解

利用程序自己编写下载文件挺有意思的。 Python中最流行的方法就是通过Http利用urllib或者urllib2模块。 当然你也可以利用ftplib从ftp站点下载文件。此外Python还提供了另外一种方法requests。 来看看三种方法是如何来下载zip文件的: import urllib import urllib2 …

springcloud(七)-Feign声明式REST调用

前言 前面我们使用的RestTemplate实现REST API调用,代码大致如下: public User findById(PathVariable Long id) {return restTemplate.getForObject("http://localhost:8084/" id, User.class);} 由代码可知,我们是使用拼接字符串…

OpenGL 各类库的解析gl glu glut freeglut glfw glew

gl.h gl库是核心库,gl中包含了最基本的3D函数,可以再本地电脑中的: C:\Program Files (x86)\MicrosoftSDKs\Windows\v7.0A\Include\gl 路径下找到gl.h头文件,打开后可以看到其中定义的上百个相关函数。 glu.h glu是实用库&#xf…

Java中throw和throws的区别

系统自动抛出的异常 所有系统定义的编译和运行异常都可以由系统自动抛出,称为标准异常,并且 Java 强烈地要求应用程序进行完整的异常处理,给用户友好的提示,或者修正后使程序继续执行。 语句抛出的异常 用户程序自定义的异常和应…

面试问题:检查牙套

这是较容易的编码任务之一,但是您仍然可以在一些初步的技术筛选中达到要求。 问题看起来像这样: 给定仅包含字符( , ) , { , } , [和]的字符串,请确定输入字符串是否有效。 括号必须以正确的顺…

python字符串长度_如何使用python获取字符串长度?哪些方法?

掌握多种python技巧,对于我们更好的灵活应用python是非常重要的,比如接下来给大家介绍的获取字节长度,那大家脑海里就该有印象了,有几种方法呢?一起来看下吧~1、使用len()函数 这是最直接的方法…

C++内存

在C中,内存分成5个区,他们分别是堆、栈、自由存储区、全局/静态存储区和常量存储区。 栈,就是那些由编译器在需要的时候分配,在不需要的时候自动清楚的变量的存储区。里面的变量通常是局部变量、函数参数等。 堆,就是那…

Dijkstra算法——计算一个点到其他所有点的最短路径的算法

迪杰斯特拉算法百度百科定义:传送门 gh大佬博客:传送门 迪杰斯特拉算法用来计算一个点到其他所有点的最短路径,是一种时间复杂度相对比较优秀的算法 O(n2)(相对于Floyd算法来说) 是一种单源最短…

浅谈java中extends与implements的区别

Extends可以理解为全盘继承了父类的功能。implements可以理解为为这个类附加一些额外的功能;interface定义一些方法,并没有实现,需要implements来实现才可用。extend可以继承一个接口,但仍是一个接口,也需要implements之后才可用。对于class而言,Extends…

注意力机制 神经网络_图注意力网络(GAT)

引言作者借鉴图神经网络中的注意力机制,提出了图注意力神经网络架构,创新点主要包含如下几个:①采用masked self-attention层,②隐式的对邻居节点采用不同权重③介绍了多头注意力机制。 在作者的Introduction中,该论文…

java版问题

1.必填项在初次保存后应该已经有值了,怎么会加载数据又是空的的? 2.客户类型 企业性质? 一般机构、上市公司.... 3.文档管理-->上传文档,如果左侧选中文档节点时,上传文档时是否默认选中文档节点。 转载于:https:/…

html5标签属性大全_HTML5中video标签如何使用

HTML5中的video标签用于播放视频文件的,在video标签中我们可以设置窗口的宽高,视频的自动播放,循环播放以及视频的封面图片等等HTML5是下一代HTML,新增了许多新的标签,这些标签实现了许多新的功能。并且还减少了对外部…