网站与数据库,北京4网站建设,wordpress的阅读量,做网站最好尽管Java到目前为止已经发布了版本13#xff0c;但是有许多生产安装都与Java 8一起运行。作为专家#xff0c;即使是最近几天#xff0c;我也多次开发Java 8代码#xff0c;我必须为这不是Java 6而感到高兴。另一方面#xff0c;作为开放源代码开发人员#xff0c;我可以… 尽管Java到目前为止已经发布了版本13但是有许多生产安装都与Java 8一起运行。作为专家即使是最近几天我也多次开发Java 8代码我必须为这不是Java 6而感到高兴。另一方面作为开放源代码开发人员我可以自由使用Java 11、12甚至13开发Java代码。 确实如此。 但是另一方面我希望使用我的代码。 开发诸如License3j或Java :: Geci之类的工具这是一种发布与Java 11兼容的字节代码的库切断了所有可能使用这些库的基于Java 8的应用程序。 我希望这些库可以从Java 8获得。 一种解决方案是在Git存储库中保持两个分支平行并拥有Java 11和Java 8版本的代码。 这是我对Java :: Geci 1.2.0版本所做的工作。 这很麻烦容易出错并且需要很多工作。 我之所以拥有这些代码是因为我的儿子也是Java开发人员他的职业生涯始于他的志愿工作。 不我没有向他施加压力。他的英语说和写的都比我好。他会定期审阅这些文章以解决我的语言破裂问题。如果他对压力有不同的看法则可以在此处随意添加任何注释直到结束为止。括号我不会删除或修改它。注意 NOTE:和)之间的任何内容都是他的意见。 另一种可能性是使用Jabel 。 在本文中我将介绍如何在Java :: Geci项目中使用Jabel。 Jabel的文档很简短但仍然很完整对于更简单的项目它的工作原理确实如此。 例如对于Licenese3j项目我实际上只需要向pom.xml添加几行。 对于一年来开发的更复杂的项目而没有考虑对Java 8兼容性的任何妥协则要复杂一些。 关于贾贝尔 Jabel是一个开源项目可从https://github.com/bsideup/jabel获得 。 如果您有Java 9项目源则可以将Jabel配置为编译过程的一部分。 它是一种注释处理器它可以参与编译过程并且可以使编译器接受各种技巧从而可以接受Java 9特性因为Java 8具有这些特性。编译器可以工作并生成Java 8Jabel不会干扰字节码的生成。 因此这是真实的因为它可以新鲜而热情地出现在Java编译器之外。 它仅指示编译器在编译代码时不要迷恋Java 9功能。 该项目的GitHub页面上很好地说明了它的工作方式以及为什么可以工作。 我在上面写的内容可能甚至不够精确。 移植问题 使用针对Java 8 JVM的Java 9功能创建Java代码时我们不仅要关注字节码版本。 使用Java 8 JVM执行的代码将使用Java 8版本的JDK如果我们碰巧使用了某些在那里不可用的类或方法则该代码将无法运行。 因此我们有两个任务 配置构建以使用Jabel生成Java 8字节码 消除Java 8中不可用的JDK调用。 配置构建 在这里我不会描述如何使用Maven将Jabel配置为构建的一部分。 它记录在网站上非常简单。 在Java :: Geci的情况下我想要一些不同的东西。 我想要一个可用于创建Java 8和Java 11目标的Maven项目。 我之所以这样是因为我希望Java :: Geci像以前一样支持JPMS并且还为在Java 11或更高版本上运行的那些项目创建最新的字节码例如类嵌套而不是桥接方法。 第一步我创建了一个名为JVM8的配置文件。 Jabel仅配置为仅在此配置文件处于活动状态时运行。 此配置文件还将发布设置为 release8 /release 因此当编译器第一次看到module-info.java文件时吓坏了。 幸运的是我可以排除JVM8概要文件中POM文件中的文件。 我还排除了javax0/geci/log/LoggerJDK9.java 稍后再讨论。 我还尝试使用Maven自动将版本号配置为具有-JVM8后缀如果它与JVM8配置文件一起运行但无法实现。 Maven是一种多功能工具可以完成许多事情如果是一个简单的项目则应该这样做。 对于Java :: Geci我无法执行此操作因为JavaGeci是一个多模块项目。 多模块项目相互引用。 至少子模块引用父模块。 子模块的版本可能与父模块的版本不同。 这是合乎逻辑的因为它们的演变和发展并不一定要结合在一起。 但是通常是这样。 在像Java :: Geci这样的项目中它具有七个子模块每个子模块的版本号与父模块相同子模块可以从父类继承所有参数依赖项编译器选项等但版本除外。 它不能继承版本因为它不知道从哪个父版本继承。 这是一个陷阱22。 Java :: Geci开发通过使用Jamal预处理程序来维护八个pom.xml文件来解决此问题。 每当构建配置发生更改时都必须在pom.xml.jam文件之一或包含的*.jim文件之一中对其进行编辑然后命令行mvn -f genpom.xml clean将重新生成所有新的pom.xml文件。 这也节省了一些重复的代码因为预处理的Jamal文件不如相应的XML文件那么冗长。 这样做的代价是必须维护使用的宏。 Java :: Geci有一个version.jim文件其中包含项目的版本作为宏。 以Java 8发行版为目标时必须将此文件中的版本更改为xyz-JVM8并且必须执行命令mvn -f genpom.xml clean 。 不幸的是这是我可能忘记的手动步骤。 创建Java 8目标后我可能也忘记删除-JVM8后缀。 为了减轻这种人为错误的风险我开发了一个单元测试以检查版本号与编译配置文件是否一致。 它标识了读取/javax0/geci/compilation.properties文件的编译配置文件。 这是项目中由Maven过滤的资源文件包含 projectVersion${project.version} profile${profile} 测试运行时属性将替换为项目中定义的实际值。 project.version是项目版本。 属性profile在两个配置文件默认和JVM8 中定义为该配置文件的名称。 如果版本和配置文件不匹配则测试失败。 遵循Java :: Geci的理念当测试本身也可以修复错误时测试不仅命令程序员修复“错误”。 它将修改version.jim文件使其包含正确的版本。 但是它不会运行生成Jamal宏的pom文件。 因此在第二次构建之后我将通过一些手动编辑工作获得xyz版本以及xyz-JVM8版本的发行文件。 消除Java 8 JDK调用 简单的通话 乍看之下这是一项简单的任务。 您不得使用Java 8 JDK中没有的方法。 我们可以使用Java 8进行任何操作因此这绝对是可能的任务。 例如每个 .repeat(tab) 必须消除。 为此我创建了一个包含静态方法的类JVM8Tools 。 例如 public static String space( int n){ final StringBuilder sb new StringBuilder( /*20 spaces*/ ); while ( sb.length() n){ sb.append(sb); } return sb.substring( 0 ,n).toString(); } 被定义在那里使用这种方法我可以写 space(tab) 而不是调用String::repeat方法。 这部分很简单。 模仿 更加困难的是实现getNestHost()方法。 Java 8中没有这样的东西但是Java :: Geci的工具模块中包含的选择器表达式使您可以使用表达式例如 Selector.compile( nestHost - (!null simpleName ~ /^Map/) ).match(Map.Entry. class ) 检查是否在Map内声明了Entry类这很简单。 即使在有人选择这样做的Java 8环境中使用此表达式也是有意义的但我不想执行截肢手术以从Java :: Geci删除此功能。 它必须被实施。 该实现检查实际的运行时并且如果该方法在JDK中存在则它通过反射进行调用。 在其他情况下它使用类的名称并尝试查找分隔内部类名称和封闭类名称的$字符来模仿功能。 当使用不同的类加载器加载同一类结构的多个实例时在极少数情况下这可能导致错误的结果。 我认为像Java :: Geci这样的工具可以使用它在执行单元测试时几乎不会发生这种情况。 Class#getNestHost反射方式调用Class#getNestHost方法还有一个速度缺陷。 如果有真正的需求我决定修复它。 记录支持 最后一个问题是日志记录。 Java 9引入了一个日志外观强烈建议库使用它。 在Java环境中日志记录是一个长期存在的问题。 问题不在于没有任何东西。 恰恰相反。 太多了 有Apache Commons LoggingLog4jLogback和JDK内置的Java util日志记录。 一个独立的应用程序可以选择它使用的日志记录框架但是如果一个库使用了一个不同的库那么即使不是不可能也很难将不同的日志消息集中到同一流中。 Java 9因此引入了一个新的Facade库可以使用它发送日志应用程序可以将输出通过Facade传递到所需的任何日志框架。 Java :: Geci使用此外观并通过它为生成器提供日志记录API。 如果是JVM8环境则不可能。 在这种情况下Java :: Geci将日志消息传递到标准Java记录器中。 要做到这一点有一个新的界面LoggerJDK由两个类实现LoggerJVM8和LoggerJDK9 。 如果目标是Java 8则后者的源代码将从编译中排除。 实际的记录器尝试通过反射获取javax0.geci.log.LoggerJDK9#factory 。 如果存在则可以使用Java 9日志记录。 如果不存在则记录器将返回工厂到javax0.geci.log.LoggerJVM8#factory 。 这样通过反射仅调用记录器工厂每个反射器仅发生一次。 日志记录本身已简化并使用目标日志记录而没有任何反射因此不会影响速度。 带走 可以在大多数库项目中支持Java 8而不会做出无法接受的妥协。 我们可以从同一源创建两个不同的二进制文件这些二进制文件支持两个不同的版本而支持Java 9及更高版本的版本不会“受苦”旧的字节码。 有一些妥协。 您必须避免调用Java 9 API并且在绝对需要的情况下您可以提供一个后备解决方案并且可以提供基于反射的运行时检测解决方案。 翻译自: https://www.javacodegeeks.com/2019/11/supporting-java-8.html