背 景
最近在使用 Flink 的 Connector 管理,在作业提交的过程中遇到下面异常
java.lang.SecurityException: sealing violation: can't seal package org.apache.flink.table.descriptors: already loaded
这个异常对于本人来说不太常见,既然抛出了这个异常,那我们好好的看下 seal package 到底是一个什么东西
关于 Package Sealing
Java JAR 提供了 Seal Package 选项。如果你使用了该选项,意味着任何程序都应该从 jar 里面加载所有类。如果从其它 Jar 中加载该包下面的类将会引发java.lang.SecurityException
这个功能的优点是带来版本的一致性,用过 Java 应该知道,Java 在运行时是严格按照Classpath 中定义的顺序进行装载和检查,当前项目中依赖很多包的情况非常常见,很有可能你的 Java 应用程序或者中间件的 Classpath 中会在不同的 Jar 文件中包含同一个Package的不同版本,这会使得程序运行产生不一致性结果,导致很难定位问题
如何使用 Package Sealing
先构建项目Sealed1
在项目的 Maven Pom 中加入插件,在 MANIFEST.MF 中增加 Sealed 为 true 选项
org.apache.maven.plugins
maven-jar-plugin
true
true
先构建项目 Sealed2, 不添加任何参数
构建项目Sealed3,对前面两个项目进行依赖,并启动
运行结果
Exception in thread "main" java.lang.SecurityException: sealing violation: package cn.hackershell is sealed
at java.net.URLClassLoader.getAndVerifyPackage(URLClassLoader.java:399)
at java.net.URLClassLoader.definePackageInternal(URLClassLoader.java:419)
at java.net.URLClassLoader.defineClass(URLClassLoader.java:451)
当我想要对 jar 中的某个包进行排除,只要显示指定对应的包名为 false 就好了,例如最终生成的 MANIFEST.MF 内容为
Sealed: true
Name: cn.hackershell.util
Sealed: false
总 结
最后发现是对包进行整体的合并的时候,误打入了一个 Sealed: true 的 MANIFEST.MF 导致 Flink 加载类失败。但是收获是我们或许可以利用这个特性,来防止一些平台版本的 Ja r和 用户版本的jar混乱的问题,最后祝大家玩的开心
参考资料