Java 17 默认禁用安全管理器,调用 System.setSecurityManager 抛出 UnsupportedOperationException,这是 JDK 明确设计变更而非 bug;需确认是否真需该机制,并迁移至模块化、运行时权限控制等现代替代方案。

Java 17 默认禁用安全管理器(Security Manager),调用 System.setSecurityManager 会直接抛出 UnsupportedOperationException,这不是 bug,而是 JDK 的明确设计变更。排查重点不是“修复异常”,而是确认是否真需 Security Manager,以及如何适配新机制。
确认是否真的需要 Security Manager
Security Manager 自 Java 1.0 引入,但长期存在性能开销大、权限模型复杂、难以维护等问题。JDK 17 已将其标记为 deprecated for removal,并在 JDK 18 中彻底移除。多数现代应用(如 Spring Boot、微服务、容器化部署)并不依赖它:
- Web 应用通常靠容器(Tomcat/Jetty)或框架(Spring Security)做访问控制,而非 JVM 级安全策略
- 沙箱需求可通过进程隔离(Docker)、最小权限用户、模块系统(
--enable-preview --add-modules jdk.incubator.foreign等替代方案)实现 - 若代码中仅用于“防止反射调用私有方法”或“拦截类加载”,应改用更明确的防御性编程(如封装校验、白名单机制)
检查第三方库是否隐式依赖 Security Manager
某些老版本库(如早期 Apache Commons Collections、部分 JNLP 客户端、遗留 RMI 工具类)会在初始化时尝试设置 Security Manager。排查方式:
- 启动时加
-verbose:class或使用jstack查看异常栈,定位首次调用setSecurityManager的类 - 搜索项目依赖:执行
mvn dependency:tree | grep -i security,重点关注含securitymanager、accesscontroller、policy的 jar - 升级依赖:例如将
commons-collections3换成commons-collections4(后者已移除 Security Manager 调用)
临时绕过(仅限测试/迁移过渡)
不推荐生产使用,但调试阶段可启用以验证行为差异:
立即学习“Java免费学习笔记(深入)”;
- 启动参数添加:
--illegal-access=permit -Djava.security.manager=allow(注意:JDK 17u 不支持该参数,实际无效;真正有效的是 JDK 16+ 的--enable-preview+ 特定 JVM 参数组合,但官方未提供开启路径) - 结论:JDK 17 中无法启用 Security Manager,所谓“绕过”本质是放弃使用——必须重构依赖逻辑
- 替代方案:用
java.lang.SecurityException手动抛出,或借助java.lang.RuntimePermission的检查逻辑模拟关键权限判定(需自行编码)
迁移到模块化与运行时权限控制
用 Java 9+ 模块系统和标准 API 替代旧安全模型:
- 限制反射:通过
Module.addOpens()/Module.addExports()显式开放包,避免运行时反射失败 - 文件/网络访问控制:改用
java.nio.file.Files的isReadable()、isWritable(),或结合 OS 层权限(如 Linux 文件 ACL) - 敏感操作审计:在关键方法入口插入自定义检查(如日志记录、租户 ID 校验),比全局 Security Manager 更精准可控


















