将Spring Boot应用程序迁移到Java 9-兼容性

随着Java 9的到来,关于如何迁移应用程序以使用模块系统的讨论越来越多。 不幸的是,大多数书面文章集中在简单的Hello world应用程序上。 或更糟糕的是,对于Spring应用程序,示例应用程序使用传统做法-例如XML。 这篇文章旨在通过为非平凡的现代Spring Boot应用程序提供逐步迁移指南来纠正这一问题。 选择这样做的示例应用程序是Spring Pet诊所

使用Java 9基本上有2个步骤:首先是兼容,然后使用成熟的模块系统。 该职位针对前者,以后的职位将考虑后者。

颠峰Java版本

一旦目标机器上有了JDK 9,第一步就是将POM中的java.version从8提升到9:

<properties>
    <!-- Generic properties -->
    <java.version> 9 </java.version>
</propertie>

现在,让我们mvn clean compile

Cobertura的失败

一路走来的第一个错误如下:

[ERROR] Failed to execute goal org.codehaus.mojo:cobertura-maven-plugin:2.7:clean (default) on project spring-petclinic:
 Execution default of goal org.codehaus.mojo:cobertura-maven-plugin:2.7:clean failed:
  Plugin org.codehaus.mojo:cobertura-maven-plugin:2.7 or one of its dependencies could not be resolved:
  Could not find artifact com.sun:tools:jar:0 at
   specified path /Library/Java/JavaVirtualMachines/jdk-9.jdk/Contents/Home/../lib/tools.jar -> [Help 1]
Cobertura是一个免费的Java代码覆盖率报告工具。
-https://github.com/cobertura/cobertura

它需要访问JDK 8(及更早版本)中的tools.jar 。 Java 9的更改之一是该库的删除。 因此,这是不兼容的。 这已经记录为问题 。 鉴于对Cobertura存储库的最后一次提交已使用了一年,只需注释掉Cobertura Maven插件即可。 然后考虑用JaCoCo代替Cobertura。

Wro4J的失败

下一个错误如下:

[ERROR] Failed to execute goal ro.isdc.wro4j:wro4j-maven-plugin:1.8.0:run (default) on project spring-petclinic:
 Execution default of goal ro.isdc.wro4j:wro4j-maven-plugin:1.8.0:run failed:
  An API incompatibility was encountered while executing ro.isdc.wro4j:wro4j-maven-plugin:1.8.0:run:
   java.lang.ExceptionInInitializerError: null
wro4j是一个免费的开源Java项目,它将帮助您轻松地缩短Web应用程序页面的加载时间。 它可以帮助您保持静态资源(js&css)的井井有条,在运行时(使用简单的过滤器)或构建时(使用maven插件)合并和最小化它们,并提供许多功能,您可能会觉得有用在处理网络资源时。
-https://github.com/wro4j/wro4j

这被称为Github问题 。 更改已合并,但是对于Java 9兼容性,此问题仍然存在,应该是2.0版本的一部分。

现在让我们注释掉Wro4J。

编译失败

此时编译项目会产生以下编译时错误:

/Users/i303869/projects/private/spring-petclinic/src/main/java/org/springframework/samples/petclinic/vet/Vet.java
Error:(30, 22) java: package javax.xml.bind.annotation is not visible
  (package javax.xml.bind.annotation is declared in module java.xml.bind, which is not in the module graph)
/Users/i303869/projects/private/spring-petclinic/src/main/java/org/springframework/samples/petclinic/vet/Vets.java
Error:(21, 22) java: package javax.xml.bind.annotation is not visible
  (package javax.xml.bind.annotation is declared in module java.xml.bind, which is not in the module graph)
Error:(22, 22) java: package javax.xml.bind.annotation is not visible
  (package javax.xml.bind.annotation is declared in module java.xml.bind, which is not in the module graph)

这意味着默认情况下,类路径上的代码无法访问此模块。 需要使用Java 9的javac--add-modules选项手动添加它。 在Maven中,可以使用maven-compiler-plugin进行设置:

<plugin>
    <artifactId> maven-compiler-plugin </artifactId>
    <version> 3.7.0 </version>
    <configuration>
        <compilerArgs>
            <arg> --add-modules </arg>
            <arg> java.xml.bind </arg>
        </compilerArgs>
    </configuration>
</plugin>

现在该项目可以编译了。

测试失败

下一步将看到单元测试因mvn test而失败。

原因是相同的,但是很难找到。 它需要检查Surefire报告。 其中一些包含以下行的异常:

Caused by: java.lang.ClassNotFoundException: javax.xml.bind.JAXBException

同样,测试代码无法访问该模块。 但是,这一次,需要配置maven-surefire-plugin

<plugin>
    <artifactId> maven-surefire-plugin </artifactId>
    <version> 2.20.1 </version>
    <configuration>
        <argLine> --add-modules java.xml.bind </argLine>
    </configuration>
</plugin>

这使测试有效。

包装失败

如果有人认为这是路的尽头,请三思。 打包阶段也会失败,并出现一个相当神秘的错误:

[ERROR] Failed to execute goal org.apache.maven.plugins:maven-jar-plugin:2.6:jar (default-jar) on project spring-petclinic:
 Execution default-jar of goal org.apache.maven.plugins:maven-jar-plugin:2.6:jar failed:
  An API incompatibility was encountered while executing org.apache.maven.plugins:maven-jar-plugin:2.6:jar:
   java.lang.ExceptionInInitializerError: null
...
Caused by: java.lang.ArrayIndexOutOfBoundsException: 1
	at org.codehaus.plexus.archiver.zip.AbstractZipArchiver.<clinit>(AbstractZipArchiver.java:116)

很难找到该解决方案 :它需要Google搜索才能找到解决方案 。 应归咎于plexus-archiver 。 在撰写本文时,只需将maven-jar-plugin升级到最新版本-3.2,即可使用Java 9兼容版本的存档器,并将解决此问题:

<plugin>
    <artifactId> maven-jar-plugin </artifactId>
    <version> 3.0.2 </version>
</plugin>

Spring Boot插件失败

至此,项目终于可以被编译,测试和打包了。 下一步是通过Spring Boot Maven插件( mvn spring-boot:run运行该应用程序。 但是它再次失败了...

[INFO] --- spring-boot-maven-plugin:1.5.1.RELEASE:run (default-cli) @ spring-petclinic ---
[INFO] Attaching agents: []
Exception in thread "main" java.lang.ClassCastException:
 java.base/jdk.internal.loader.ClassLoaders$AppClassLoader cannot be cast to java.base/java.net.URLClassLoader
	at o.s.b.devtools.restart.DefaultRestartInitializer.getUrls(DefaultRestartInitializer.java:93)
	at o.s.b.devtools.restart.DefaultRestartInitializer.getInitialUrls(DefaultRestartInitializer.java:56)
	at o.s.b.devtools.restart.Restarter.<init>(Restarter.java:140)
	at o.s.b.devtools.restart.Restarter.initialize(Restarter.java:546)
	at o.s.b.devtools.restart.RestartApplicationListener.onApplicationStartingEvent(RestartApplicationListener.java:67)
	at o.s.b.devtools.restart.RestartApplicationListener.onApplicationEvent(RestartApplicationListener.java:45)
	at o.s.c.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:167)
	at o.s.c.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:139)
	at o.s.c.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:122)
	at o.s.b.context.event.EventPublishingRunListener.starting(EventPublishingRunListener.java:68)
	at o.s.b.SpringApplicationRunListeners.starting(SpringApplicationRunListeners.java:48)
	at o.s.b.SpringApplication.run(SpringApplication.java:303)
	at o.s.b.SpringApplication.run(SpringApplication.java:1162)
	at o.s.b.SpringApplication.run(SpringApplication.java:1151)
	at org.springframework.samples.petclinic.PetClinicApplication.main(PetClinicApplication.java:32)

这是一个已记录的问题 ,Spring Boot Dev Tools v1.5与Java 9 兼容。

幸运的是,此错误已在Spring Boot 2.0.0.M5中修复。 不幸的是,在撰写本文时,此特定版本尚不可用。 因此,现在,让我们删除开发工具并尝试再次运行。 它再次失败,但是这次例外是一个熟悉的例外:

Caused by: java.lang.ClassNotFoundException: javax.xml.bind.JAXBException

让我们将必需的参数添加到spring-boot-maven-plugin

<plugin>
    <groupId> org.springframework.boot </groupId>
    <artifactId> spring-boot-maven-plugin </artifactId>
    <configuration>
        <jvmArguments> --add-modules java.xml.bind </jvmArguments>
    </configuration>
    ...
</plugin>

该应用程序终于可以启动并可以访问了!

结论

在JDK 9上运行非常重要的旧版应用程序需要花费一些精力。 更糟糕的是,必须保留一些重要功能:代码覆盖率和Web性能增强。 相反,唯一的好处就是字符串存储空间的改善。 在下一篇博客文章中,我们将尝试改善这种情况,以实际使用应用程序中的模块。

这篇文章的完整源代码可以在Github上找到。

翻译自: https://blog.frankel.ch/migrating-to-java-9/1/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值