java9迁移注意事项

本文主要研究下迁移到java9的一些注意事项。

迁移种类

1、代码不模块化,先迁移到jdk9上,好利用jdk9的api
2、代码同时也模块化迁移

几点注意事项

不可读类

比如sun.security.x509,在java9中归到java.base模块中,但是该模块没有export该package

可以通过运行的时候添加--add-exports java.base/sun.security.x509=ALL-UNNAMED来修改exports设定

内部类

比如sun.misc.Unsafe,原本只想让oracle jdk team来使用,不过由于这些类应用太广泛了,为了向后兼容,java9做了妥协,只是将这些类归到了jdk.unsupported模块,并没有限定其可读性。

➜  ~ java -d jdk.unsupported
jdk.unsupported@9
exports com.sun.nio.file
exports sun.misc
exports sun.reflect
requires java.base mandated
opens sun.misc
opens sun.reflect

删除的类

java9删除了sun.misc.BASE64Encoder,这种情况只能改用其他api,比如java.util.Base64

classpath vs module-path

java9引入了模块系统,同时自身的jdk也模块化了,引入了module-path,来屏蔽classpath,也就是说在java9优先使用module-path,毕竟jdk本身都模块化了,应用本身没有模块化的话,java9通过unnamed modules及automatic modules机制来隐式模块化,当然classpath在java9上还能继续使用,比如配合module-path使用等。

没有模块化的jar在classpath会被归到unnamed modules;在module-path则会被自动创建为automatic modules(一个automatic modules会声明transitive依赖所有named和unnamed module,然后导出自身的package)

一个包名不能在多个模块中出现(split packages)

因为模块中可以exports指定包给其他模块,如果多个模块exports同样的包名会造成混乱,特别若有其他类库同时requires这两个模块,就不知道该引用那个模块的了。

传递依赖

如果一个模块的接口参数或返回类型使用了其他模块的类,则建议requires transitive它依赖的模块

小心循环依赖

在设计模块的时候,要尽可能考虑到是否会有循环依赖的问题,如果有则需要重新设计

使用services来实现optional依赖

services特别适合用来解耦调用方与实现类依赖的问题,如果接口有多种实现类,调用方不必要requires所有的实现类,只需要requires接口即可,使用services类型来加载实现类的实例。通过在module-path去动态添加实现模块实现解耦。

模块版本管理

module-info.java不支持声明版本号,但是创建jar包的时候,可以通过--module-version设置。不过模块系统查找模块的时候还是使用模块名来查找(如果module-path里头有多个重名模块,则模块系统知会使用找到的第一个,自动忽略后续的同名模块),版本依赖问题不在模块系统解决范畴内,交由maven之类的依赖管理工具去管理。

模块资源访问

模块化之后资源文件也收到保护,只能由该模块去访问本模块自身的资源文件,如果需要跨模块访问,也必须借助ModuleLayer找到目标模块,再调用目标模块去加载该模块的资源文件。

反射的使用

这里涉及到deep reflection问题,所谓的deep reflection就是通过反射去调用一个class的非public元素。module-info.java的exports声明package只是允许该package直接所属的类允许访问其public元素,并不允许反射调用非public元素。

反射在模块系统里头需要特殊声明才允许使用(使用opens声明允许deep reflection),这样就导致很多使用反射的类库诸如spring,需要额外配置才能迁移到java9。解决方案有两个:一个是opens package包名给需要反射的模块,比如spring.beans等;一个就是直接opens整个模块。

默认--illegal-access=permit,同时该设置只适用于java9之前的package在java9被不允许访问,不适用于java9中新的不允许访问的package.(建议迁移到模块化系统时设置为deny)

不过就是在模块系统中包名不一样就属于不同的包,没有继承关系,比如com.service.func1与com.service.func2这两个是不同的包,你不能只opens com.service,必须分别指定这样就导致需要open的的package比较多。因此open整个module可能更省事一点,但也属于比较粗暴的做法。

上面的做法是在原来module-info.java里头去做修改,另外一种是在执行java或javac的时候通过指定的命令来修改原来的关系。比如

java ... --add-opens source-module/source-package=target-module

如果需要导出给unnamed modules,则target-module为ALL-UNNAMED

当然如果是新的系统,那就不建议使用反射了,可以使用MethodHandles及VarHandles。

常见问题和措施

ClassNotFoundException/NoClassDefFoundError

比如javax.xml.bind.JAXBException,JAXB已经归入到java.xml.bind模块,在java命名后面添加

--add-modules java.xml.bind

如果图省事,把$JAVA_HOME及所有第三方类库添加到module-path,然后来个

--add-modules ALL-MODULE-PATH

illegal reflective access by xxx to method java.lang.ClassLoader.defineClass

反射原因引起,由于旧系统没有module-info,因此在java命名添加参数加以修改

--add-opens java.base/java.lang=ALL-UNNAMED

确定依赖的模块

通过IDE或者jdeps分析

jdeps --class-path 'classes/lib/*' -recursive -summary app.jar

jdeps只是静态代码分析,如果有使用反射用的类jdeps分析不出来,需要自己手工requires,如果dependency是optional的,可以requires static

对模块单元测试的可读性问题

如果单元测试时单独模块的话,可以在运行时通过--add-exports或--add-opens来授予单元测试模块对目标模块的可读性及反射能力。另外由于split packages问题,单元测试类的包名不能跟目标模块包名重复。原来maven工程那种test

小结

可以分两步走迁移到java9,首先是先不模块化,只先跑在jdk9上;然后再模块化。

doc

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

推荐阅读更多精彩内容