上周,我试图制作一个Spring Boot应用程序 -与Java 9兼容的著名Pet Clinic。 这并不容易。 一路上我不得不放弃很多功能。 总而言之,我得到的唯一好处是改进了字符串内存管理。
本周,我想通过全面拥抱Java 9模块系统来继续进行迁移。
配置模块元数据
Java 9中的模块信息是通过module-info.java
文件实现的。 第一步是在源目录的根目录下使用模块名称创建一个这样的文件:
moduleorg.springframework.samples.petclinic{
}
其余的旅程可以是天堂或地狱。 我很幸运从IntelliJ IDEA许可证中受益。 IDE会准确告知它无法读取的类,并使用向导将其放入模块文件中。 最后,它看起来像这样:
moduleorg.springframework.samples.petclinic{
requiresjava.xml.bind;
requiresjavax.transaction.api;
requiresvalidation.api;
requireshibernate.jpa;
requireshibernate.validator;
requiresspring.beans;
requiresspring.core;
requiresspring.context;
requiresspring.tx;
requiresspring.web;
requiresspring.webmvc;
requiresspring.data.commons;
requiresspring.data.jpa;
requiresspring.boot;
requiresspring.boot.autoconfigure;
requirescache.api;
}
请注意,可以删除maven-compiler-plugin
和maven-surefire-plugin
中的模块配置。
无辅助配置
如果您碰巧处于不太理想的环境中,则过程如下:
- 运行
mvn clean test
- 分析日志中的错误以获取违规软件包
- 找到所述程序包的JAR
- 如果JAR是模块,则将模块名称添加到所需模块列表中
- 如果不是,请计算自动模块名称,并将其添加到需求模块列表中
例如:
[ERROR] ~/spring-petclinic/src/main/java/org/springframework/samples/petclinic/system/CacheConfig.java:[21,16] package javax.cache is not visible [ERROR] (package javax.cache is declared in the unnamed module, but module javax.cache does not read it)
javax.cache
位于cache-api-1.0.0.jar
。 它不是模块,因为JAR中没有module-info
。 自动模块名称为cache.api
。 根据requires
将其写入模块中。 冲洗并重复。
ASM故障
从本文的第一部分开始,我就意识到Spring Boot 1.5不会兼容Java 9。 我们开始做吧。
将Spring Boot升级到2.0.0.M5需要对模块依赖项进行一些更改:
-
hibernate.validator
到org.hibernate.validator
-
validation.api
到java.validation
当您认为它可能会起作用时:
Caused by: java.lang.RuntimeException at org.springframework.asm.ClassVisitor.visitModule(ClassVisitor.java:148)
此问题已被记录 。 此时,显式声明主类可以解决此问题。
<plugin>
<groupId> org.springframework.boot </groupId>
<artifactId> spring-boot-maven-plugin </artifactId>
<configuration>
<jvmArguments> --add-modules java.xml.bind </jvmArguments>
<mainClass> org.springframework.samples.petclinic.PetClinicApplication </mainClass>
</configuration>
...
</plugin>
Javassist失败
现在可以使用mvn clean spring-boot:run
测试该应用程序了。 不幸的是,我们的方式出现了一个新的例外:
2017-10-16 17:20:22.552 INFO 45661 --- [ main] utoConfigurationReportLoggingInitializer : Error starting ApplicationContext. To display the auto-configuration report re-run your application with 'debug' enabled. 2017-10-16 17:20:22.561 ERROR 45661 --- [ main] o.s.boot.SpringApplication : Application startup failed org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaAutoConfiguration.class]: Invocation of init method failed; nested exception is org.hibernate.boot.archive.spi.ArchiveException: Could not build ClassFile
快速搜索将重定向到Java 9与Javassist之间的不兼容性 。 Javassist是这里的元凶。 通过Hibernate可传递地需要Spring Data JPA依赖项。 要解决此问题,请排除依赖项,然后添加最新版本:
<dependency>
<groupId> org.springframework.boot </groupId>
<artifactId> spring-boot-starter-data-jpa </artifactId>
<exclusions>
<exclusion>
<artifactId> javassist </artifactId>
<groupId> org.javassist </groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId> org.javassist </groupId>
<artifactId> javassist </artifactId>
<version> 3.22.0-GA </version>
<scope> runtime </scope>
</dependency>
幸运的是,版本是兼容的-至少对于我们的用法而言是兼容的。
有用!
我们做到了! 如果到达这一点,您应该轻拍肩膀,啤酒或其他您认为应得的东西。
锦上添花,可以重新添加Dev Tools依赖项。
结论
迁移到Java 9需要使用Jigsaw,无论您是否喜欢。 至少,这意味着痛苦的尝试和错误搜索下一个修复过程, 并删除了构建过程中的重要步骤。 对于库/框架开发人员来说,在其内部API中增加访问控制层很有趣,但对于应用程序而言则要少得多。 在此阶段,不值得转向Java 9。
我希望在几个月后再次进行这项实验,并注意到情况有所改善。