生产环境反射权限控制由运行时环境、模块系统和启动参数共同决定:Java 17+ 依赖 --illegal-access=deny 和 --add-opens 参数,.NET Framework 依赖程序集信任级别与权限策略,现代 .NET 已移除 CAS。

在生产环境中,反射权限控制不是靠“配置一个文件”来实现的,而是由运行时环境、模块系统和启动参数共同决定的一套约束机制。Java 和 .NET 两大主流平台的处理逻辑完全不同,且都已放弃传统基于 policy 文件或权限声明的粗粒度控制方式。
Java 17+:靠 JVM 启动参数而非配置文件
SecurityManager 已被移除,setAccessible(true) 不再触发任何权限检查——这意味着你无法通过修改某个 policy 文件来拦截它。真正起效的是以下 JVM 参数组合:
-
--illegal-access=deny:强制关闭所有未显式开放的跨模块反射访问,一触即抛
InaccessibleObjectException -
--add-opens 模块/包=调用方模块名:只对指定模块中的指定包开放反射,例如:
--add-opens java.base/java.lang=ALL-UNNAMED(允许类路径代码访问java.lang) -
同一模块内反射默认可用:模块内部成员无需额外开放,但模块边界必须清晰(需有
module-info.java) - Spring Boot 用户需在
spring-boot-maven-plugin的jvmArguments或容器启动脚本中透传这些参数,否则不生效
.NET Framework:依赖程序集信任级别与权限策略
.NET 中没有单独的“反射权限控制文件”,实际生效的是运行时加载上下文中的权限集(Permission Set)和程序集的强名称/签名信任状态:
- 仅完全信任的程序集可调用
BindingFlags.NonPublic访问非公共成员;沙盒环境(如部分信任 AppDomain)默认禁止 - 访问
internal(C#)或Friend(VB)成员,要求调用方与目标成员在同一程序集,或显式使用[InternalsVisibleTo]声明可见性 - 反射调用安全关键(Security-Critical)成员时,会触发
ReflectionPermissionFlag.MemberAccess检查,该权限必须由 AppDomain 策略显式授予 - 现代 .NET(Core / 5+)已移除 Code Access Security(CAS),上述限制仅适用于遗留的 .NET Framework 应用
替代方案比“控制反射”更可靠
试图在运行时“管控反射行为”本质是防御失效后的补救。高安全场景应优先规避反射本身:
- 用 VarHandle 替代字段反射读写,性能更高且受模块封装保护
- 通过 SPI(Service Provider Interface) 解耦扩展点,避免硬编码反射调用
- 采用 编译期代码生成(如 Annotation Processing、Source Generation),把动态逻辑转为静态字节码
- 对必须保留的反射路径,用 模块封装 + --illegal-access=deny 构建第一道防线,再配合静态扫描(如 SpotBugs + 自定义规则)在 CI 阶段拦截非法
setAccessible调用
不复杂但容易忽略:真正的反射权限控制,始于模块设计,成于启动参数,稳于编译约束。










