Class.getSigners() 方法自 Java 9 起被弃用、Java 17 彻底移除,因其返回未定义的 Object[]、依赖 JAR 签名路径且不兼容模块系统;应改用 CodeSource.getCertificates() 或解析 META-INF 签名文件获取 X.509 证书。

Class.getSigners() 方法在现代 Java 中已被弃用且实际不可用,它从 Java 9 开始被标记为 @Deprecated(since="9", forRemoval=true),并在 Java 17+ 中彻底移除(JDK-8260351)。该方法从未可靠返回证书链信息,其行为依赖于类加载时是否通过 JAR 清单签名验证,且返回值类型为 Object[],无法直接解析为 X509Certificate 或其他标准证书类型。
为什么 getSigners() 不应再使用
该方法设计初衷是配合早期 Java 安全模型(如 SecurityManager)提供签名者身份,但存在根本缺陷:
- 返回数组内容未定义:可能为
null、空数组,或包含任意实现类(如SunCertPathBuilderException实例),无统一规范 - 不区分签名算法或证书格式:无法获取证书序列号、颁发者、有效期等关键字段
- 依赖 JAR 签名验证路径:仅当类由
URLClassLoader加载且 JAR 包含有效META-INF/*.SF和签名文件时才可能非空,普通模块路径(--module-path)或类路径(-cp)下几乎总为空 - 与现代模块系统和强封装冲突:Java 9+ 模块系统绕过传统签名检查机制
替代方案:从 JAR 文件中提取签名证书
若需获取类所属 JAR 的签名证书,应直接解析 JAR 的 META-INF/ 目录下的签名文件(如 XXX.SF、XXX.DSA 或 XXX.RSA):
- 通过
Class.getResource("/META-INF/MANIFEST.MF")定位 JAR,再用java.util.jar.JarFile打开并读取META-INF/*.RSA等签名文件 - 使用
java.security.cert.CertificateFactory解析 DER 编码的证书数据(签名文件末尾通常嵌入 X.509 证书) - 示例关键步骤:
JarFile jar = new JarFile(jarUrl.toURI().getPath());InputStream certStream = jar.getInputStream(jar.getEntry("META-INF/ABC.RSA"));CertificateFactory cf = CertificateFactory.getInstance("X.509");X509Certificate cert = (X509Certificate) cf.generateCertificate(certStream);
运行时验证签名的正确方式
生产环境应避免依赖静态签名信息,改用标准安全机制:
立即学习“Java免费学习笔记(深入)”;
- 使用
CodeSource.getCertificates():若类由URLClassLoader加载且 JAR 已验证,可通过clazz.getProtectionDomain().getCodeSource().getCertificates()获取证书数组(返回Certificate[],类型安全) - 启用 JAR 验证:启动时添加
-Djar.verify=true(Java 8 及以前),或确保 JAR 签名符合 JAR 规范 - 自定义
SecureClassLoader:重写loadClass并在defineClass后调用verifyCodeSource进行主动校验
注意事项与限制
所有签名检查均受以下因素影响:
- Java 版本差异:Java 8 支持较完整,Java 9+ 默认禁用
SecurityManager,签名验证逻辑大幅简化 - 类加载器类型:
BootstrapClassLoader和PlatformClassLoader加载的类无签名信息;仅URLClassLoader及其子类可能携带 - 模块化影响:JPMS 模块(
module-info.class)不支持传统 JAR 签名,需使用jmod或jlink签名工具 - 安全策略:即使证书有效,仍需
SecurityManager配置权限(如RuntimePermission("getClassLoader"))才能访问证书链


















