accesscontrolexception 是 securitymanager 明确拒绝敏感操作所致,需先确认 jvm 是否启用安全管理器(system.getsecuritymanager() != null),再通过堆栈定位被拦截的权限类型(如 filepermission)及触发代码,严格匹配策略文件中 codebase 路径、权限 target/actions 格式;jdk 17+ 已移除 securitymanager 原生支持,相关配置无效。

AccessControlException 报错时先看堆栈里 checkPermission 调用链
这个异常不是运行时随便抛的,而是 SecurityManager 在执行 checkPermission 时明确拒绝了某次敏感操作。关键不是“为什么没权限”,而是“谁在检查什么权限”。堆栈里往上找,一定能看到类似 FilePermission、SocketPermission 或 RuntimePermission 的字样——这才是真实被拦的操作类型。
常见错误现象:AccessControlException: access denied ("java.io.FilePermission" "/tmp/test.txt" "read"),说明代码试图读文件,但策略没授权;又或者 access denied ("java.lang.RuntimePermission" "createClassLoader"),说明用了自定义类加载器但没开权限。
- 别急着改
java.policy,先确认当前 JVM 是否真启用了安全管理器(System.getSecurityManager() != null) - 检查堆栈最顶上几行,定位是哪行业务代码触发的检查(比如
new FileInputStream(...)或Class.forName(...)) - 注意 JDK 9+ 默认不启用
SecurityManager,如果看到这个异常,大概率是你显式加了-Djava.security.manager或代码里调了System.setSecurityManager(...)
策略文件里 grant 块的 codeBase 必须精确匹配 JAR 或 classpath 路径
codeBase 不是模糊匹配,也不是按包名生效,它匹配的是类实际加载来源的 URL。写错一个斜杠、少一个 file: 前缀、路径里用了相对路径但 JVM 当前目录变了,都会导致整个 grant 块失效。
使用场景:你打包了一个 app.jar,里面有个类要读配置文件,你在 my.policy 里写了授权,但始终不生效。
立即学习“Java免费学习笔记(深入)”;
-
codeBase "file:/opt/myapp/app.jar"—— 正确,绝对路径,末尾无斜杠 -
codeBase "file:/opt/myapp/"—— 错误,这是目录,JAR 文件不会被识别为 codeBase 源 -
codeBase "file:app.jar"—— 错误,相对路径依赖启动目录,极不可靠 - 如果类来自模块路径(JDK 9+),
codeBase对模块无效,得用module语法(但实际极少用)
权限项里的 target 和 actions 大小写、空格、引号都必须严格符合文档定义
FilePermission 的 target 是路径字符串,actions 是逗号分隔的小写动作(如 "read,write"),多一个空格或写成 "Read" 就完全不匹配。Java 权限系统不做任何 normalize 或容错。
性能影响:每次权限检查都要遍历所有 grant 块,再逐个比对 codeBase 和权限项,所以策略文件别堆几十个重复块。
-
permission java.io.FilePermission "/tmp/-", "read,write";—— 正确,-表示子路径递归 -
permission java.io.FilePermission "/tmp/", "read, write";—— 错误,actions里多了空格 -
permission java.lang.RuntimePermission "setSecurityManager";—— 正确,这个权限没有actions字段 -
permission java.net.SocketPermission "example.com:80", "connect";—— 注意主机名和端口之间是英文冒号,不是中文或全角
JDK 17+ 环境下 SecurityManager 已被彻底移除,硬配策略文件也没用
从 JDK 17 开始,SecurityManager 类还在,但所有方法都直接抛 UnsupportedOperationException。如果你在 JDK 17+ 上看到 AccessControlException,只有一种可能:你的应用自己实现了 SecurityManager 子类并主动调用 checkPermission,或者用了老版本框架(如早期 Tomcat)自带的定制安全管理器。
兼容性影响:不要假设 -Djava.security.policy=my.policy 在新 JDK 里还能起作用。JVM 启动时会静默忽略该参数,也不会报错。
- 查 JDK 版本:
java -version输出含17或更高,基本可排除原生策略机制 - 运行时验证:
System.getSecurityManager()返回null或抛UnsupportedOperationException,就说明原生机制已失效 - 真正需要沙箱隔离的场景,现在应转向容器、模块系统(
java --module-path)、或SecurityManager替代方案(如 Java Agent + 字节码插桩)
最容易被忽略的一点:很多团队在升级 JDK 后,还留着旧的 java.policy 文件和启动参数,以为它还在生效,结果权限问题排查方向完全跑偏。










