是时候迁移到Java 11了,Java 8到11迁移实战

JDK 8将停止支持

Oracle JDK 8将于2019年1月(从现在起153天)停止发布公共更新,时间不多了,所以虫虫认为现在是最好的时机迁移到最新版JDK版本,享受新版本的各种黑魔法和新功能了。

另外,在虫虫以前的文章中也提到过,从JDK 11开始,其发布周期变为每6个月一个新版本,每3年发布一个新的LTS版本(下一个是JDK 11)。

值得一提的是,发布的公开使用的Oracle JDK将支持OpenJDK源代码进行编译而无需更改。

Java会收费吗?

ORACLE确保,不会对Java公共开放不会收费。所有Java/JDK开发基于OpenJDK版本库中完成,所有修复和增强功能都将推送到该开放库。

另外,三方公司也都有自己JRE实现,比如谷歌,Azul和RedHat等,以及IBM开源的Java/JDK实现OpenJ9:

向Java 11迁移

在Java 9,10和即将发布的Java 11 LTE,我们来着重介绍下如何迁移Java应用程序和模块及其可能存在的未解决的问题。虽然类似的文章问多,但是深入的太少,大多数文章都集中在简单的Hello World应用程序上。

本文我们将介绍个基于Spring Boot框架的应用程序为实例分步介绍迁移具体过程。选择这样做的示例应用程序是Spring PetClinic,一个使用WebMVC,Actuator,Cache,Data JPA,Thymeleaf和Test starters的Spring Boot 2示例应用程序。完全迁移到Java 11基本上有三个主要过程:

1.使用JDK 11运行现有Java应用程序。

2.使用Java 11编译应用程序。

3.模块化应用程序以使用模块系统。

如果你还没有准备好同时做这三件事,那请追随虫虫脚本开始。

JDK 11开发环境构建

首先,你需要为你的操作系统下载并安装JDK 11。

首先更新你喜欢的IDE以支持Java模块系统:

根据各自的IDE官网下载相应模块(地址略):

Eclipse IDE,IntelliJ IDEA,Apache NetBeans

1.使用JDK 11运行现有Java应用程序

为什么要从JDK 8升级到JDK 11?因为我们将能享受到以下这些的黑魔法:

JDK 11 黑魔法

继Java 8后最新LTS长期支持版本(如果你拥有商业许可证)。

完全支持Linux容器(包括Docker)。

支持G1上的并行完全垃圾收集。

免费应用程序类,数据共享功能。

免费的低耗能飞行记录仪和堆分析仪。

备用存储设备上的堆分配。

新的默认根权限证书集。

新的ZGC和Epsilon垃圾收集器。

Ahead-of-time编译和GraalVM。

最新的HTTPS安全协议TLS 1.3。

JShell。

支持"shebang"Java脚本文件! #!/bin/java

运行你的应用程序

这是一个非常简单的步骤,使用早期Java版本创建的应用程序都可以在JDK 11上运行而不会出现重大问题,除非你得依赖模块中包括JEP-320中从JDK中删除的Java EE或CORBA模块。

如果缺少类,你可能需要显式添加java.activation,java.transaction和java.xml.bind依赖项。在类文件错误的情况下,你将需要更新Java字节码增强库,如ASM,bytebuddy,javassist或cglib等。

2.使用Java 11编译应用程序

为什么要将源代码升级到Java 11?

局部变量类型推断(var关键字)。

新的本机不可修改集合API。

新的反应流API。

改进的流/谓词/可选API。

改进的系统过程API。

改进的文件API。

支持HTTP/2。

标准Java异步HTTP客户端。

多版本JAR。

详细步骤:

1.克隆Spring PetClinic存储库

git clone github:spring-projects/spring-petclinic.git

2.更新版本信息

打开pom.xml并更新java.version属性

<java.version>11java.version>

<maven.compiler.source>${java.version}maven.compiler.source>

<maven.compiler.target>${java.version}maven.compiler.target>

3.删除cobertura-maven-plugin引用

因为它不支持JDK 11,而且也有年头不维护了。你可以使用支持较新JDK版本的JaCoCo。

4.更新javassist和mockito-core依赖项

<dependency>

<groupId>org.javassistgroupId>

<artifactId>javassistartifactId>

<version>3.23.1-GAversion>

dependency>

<dependency>

<groupId>org.mockitogroupId>

<artifactId>mockito-coreartifactId>

<version>2.20.0version>

<scope>testscope>

dependency>

5.包括mockito-core depende

...

org.mockito

mockito-core

2.20.0

...

6.使用最新的asm依赖项将maven-compiler-plugin更新到3.7.0+版本

org.apache.maven.plugins

maven-compiler-plugin

3.7.0

${java.version}

org.ow2.asm

asm

6.2

7.使用最新的asm依赖项将maven-surefire-plugin更新到2.21.0+版本

maven-surefire-plugin

2.21.0

org.ow2.asm

asm

6.2

8.包含java.xml.bind模块依赖项,因为JEP-320在JDK 11中删除了这些模块

<dependency>

<groupId>org.glassfish.jaxbgroupId>

<artifactId>jaxb-runtimeartifactId>

<version>2.4.0-b180608.0325version>

dependency>

9.在pom.xml中包含GlassFish JAXB存储库

<repositories>

<repository>

<id>jvnet-nexus-stagingid>

<url>http://maven.java.net/content/repositories/staging/url>

<layout>defaultlayout>

repository>

repositories>

10.使用spring-boot-maven-plugin运行应用程序

./mvnw spring-boot:run

然后可以通过浏览器访问应用程序界面:localhost:8080

11.打包应用程序并运行测试

./mvnw clean package

12.使用打包的可执行jar运行应用程序

java -jar target/spring-petclinic-2.0.0.BUILD-SNAPSHOT.jar

现在,你可以使用Java 11编译和运行应用程序,但还没用到模块系统。

3.模块化应用程序以使用模块系统

为什么要迁移到模块系统?

配置更可靠:用程序组件声明显式依赖的方法来替换脆弱的,容易出错的类路径机制。

强封装:允许组件声明其中哪些公共类型可供其他组件访问,哪些不可访问。

为你的应用程序创建最小的JRE映像

•减少应用程序内存占用量。

•优化应用程序启动时间。

具体步骤如下:

1.创建模块文件module-info.java

在src/main/java目录中创建一个名为module-info.java的文件,其中包含以下内容:

module spring.petclinic {

}

现在,当你尝试编译应用程序时,你会看到如下所示很多错误告警:

Error:(19, 27) java: package org.springframework.boot is not visible

(package org.springframework.boot is declared in module spring.boot, but module spring.petclinic does not read it)

这表明应用程序已经表现为模块化布局,并且必须连接模块以进行编译和运行时。

你可以使用Maven依赖项插件解析目标列出当前在类路径中的所有模块名称,并将它们添加到module-info中:

./mvnw compile org.apache.maven.plugins:maven-dependency-plugin:3.1.1:resolve

注意:上面的命令不排除传递依赖项或包括JDK模块。

遗憾的是,由于许多原因,jdeps无法帮助你生成模块描述列表,但主要是因为第三方库尚未添加模块系统描述,它们被视为特殊的自动模块。

最终的模块描述符应如下所示:

open module spring.petclinic {

requires cache.api;

requires java.activation;

requires java.instrument;

requires java.persistence;

requires java.sql;

requires java.transaction;

requires java.validation;

requires java.xml.bind;

requires org.hibernate.validator;

requires spring.beans;

requires spring.boot;

requires spring.boot.autoconfigure;

requires spring.context;

requires spring.core;

requires spring.data.commons;

requires spring.data.jpa;

requires spring.tx;

requires spring.web;

requires spring.webmvc;

requires jdk.unsupported;

}

注意:由于Spring Framework和Hibernate JPA的反射要求,open关键字是必需的,jdk.unsupported是sun.misc.Unsafe的survivors。

2.构建并引入modules目录

引入maven-jar-plugin以创建应用程序jar(仅限类)并将其复制到modules目录。

<plugin>

<artifactId>maven-jar-pluginartifactId>

<version>3.1.0version>

<configuration>

<outputDirectory>

${project.build.directory}/modules

outputDirectory>

configuration>

plugin>

3.引入maven-dependency-plugin以将运行时依赖项复制到模块目录。

<plugin>

<groupId>org.apache.maven.pluginsgroupId>

<artifactId>maven-dependency-pluginartifactId>

<version>3.1.1version>

<executions>

<execution>

<phase>packagephase>

<goals>

<goal>copy-dependenciesgoal>

goals>

<configuration>

<outputDirectory>

${project.build.directory}/modules

outputDirectory>

<includeScope>runtimeincludeScope>

<excludeArtifactIds>

spring-boot-devtools

excludeArtifactIds>

configuration>

execution>

executions>

plugin>

注意:应该从模块中排除spring-boot-devtools依赖项。

4.包括java.persistence和java.transaction模块依赖项

它们修复了更新版本的自动模块问题:

<dependency>

<groupId>org.hibernate.javax.persistencegroupId>

<artifactId>hibernate-jpa-2.1-apiartifactId>

<version>1.0.2.Finalversion>

dependency>

<dependency>

<groupId>org.jboss.spec.javax.transactiongroupId>

<artifactId>jboss-transaction-api_1.2_specartifactId>

<version>1.1.1.Finalversion>

dependency>

同样增加javax.transaction依赖给 spring-boot-starter-data-jpa.

<exclusions>

<exclusion>

<artifactId>javax.transaction-apiartifactId>

<groupId>javax.transactiongroupId>

exclusion>

exclusions>

注意:当存在module-info.java并且启用了fork进程时,surefire会创建一个包含模块和未命名模块的混合类路径,从而导致模块可见性问题,这会阻止应用程序启动。

6.打包并测试应用程序

./mvnw clean package

7.使用Java模块系统运行应用程序

java --add-opens java.base/java.lang=spring.core,javassist

--module-path target/modules

--module spring.petclinic/org.springframework.samples.petclinic.PetClinicApplication

注意:由于Spring和Hibernate依赖项会有请求JDK反射访问,因此需要--add-opens。

8.设置main-class属性

使用以下命令设置模块main-class属性,删除使用module参数指定的主类:

jar --update

--file=target/modules/spring-petclinic-2.0.0.BUILD-SNAPSHOT.jar

--main-class=org.springframework.samples.petclinic.PetClinicApplication

9.为了自动执行上一步,你可以添加exec-maven-plugin:

<plugin>

<groupId>org.codehaus.mojogroupId>

<artifactId>exec-maven-pluginartifactId>

<version>1.6.0version>

<executions>

<execution>

<id>module-main-classid>

<phase>packagephase>

<goals>

<goal>execgoal>

goals>

<configuration>

<executable>jarexecutable>

<arguments>

<argument>

--update

argument>

<argument>

--file=${project.build.directory}/modules/${project.build.finalName}.jar

argument>

<argument>

--main-class=org.springframework.samples.petclinic.PetClinicApplication

argument>

<argument>

--module-version=${project.version}

argument>

arguments>

configuration>

execution>

executions>

plugin>

10.现在你可以在没有显式主类声明的情况下运行应用程序:

./mvnw clean package

java --add-opens java.base/java.lang=spring.core,javassist

--module-path=target/modules

--module spring.petclinic

注意:由于MJAR-238,Maven还不支持开箱即用。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,542评论 6 504
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,822评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,912评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,449评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,500评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,370评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,193评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,074评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,505评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,722评论 3 335
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,841评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,569评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,168评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,783评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,918评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,962评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,781评论 2 354

推荐阅读更多精彩内容