JEP 451: 准备禁止动态加载代理
JEP 451(Prepare to Disallow the Dynamic Loading of Agents)已从目标状态完成,并将在JDK 21中实现。该JEP的最初目标是默认禁止将代理动态加载到正在运行的JVM中,但经过演变,现改为在动态加载代理时发出警告。该JEP的目标包括:重新评估可维护性与完整性之间的平衡;确保大多数不需要动态加载代理的工具不受影响。
主要目标
该提案的主要目标是为未来JDK版本做准备,默认情况下将禁止将代理加载到正在运行的JVM中。这一变化旨在重新评估可维护性(涉及对运行代码的临时更改)与完整性(假设运行代码不会被任意更改)之间的平衡。值得注意的是,大多数不需要动态加载代理的工具将不受此变化影响。
JDK 21中的实现
在JDK 21中,动态加载代理仍然被允许,但JVM会在发生时发出警告。例如:
WARNING: A {Java,JVM TI} agent has been loaded dynamically (file:/u/bob/agent.jar)
WARNING: If a serviceability tool is in use, please run with -XX:+EnableDynamicAgentLoading to hide this warning
WARNING: If a serviceability tool is not in use, please run with -Djdk.instrument.traceUsage for more information
WARNING: Dynamic loading of agents will be disallowed by default in a future release如果开发者希望工具在动态加载代理时不发出警告,则必须在命令行中使用-XX:+EnableDynamicAgentLoading选项。
代理的作用与滥用
Java平台中的代理是可以在应用程序运行时修改其代码的组件。它们由JDK 5中的Java Platform Profiling Architecture引入,主要用于工具(如性能分析器)对类进行插桩,即在不改变代码行为的情况下,修改类以发出事件供外部工具使用。
然而,随着时间的推移,一些高级开发者发现了代理的其他用途,例如Aspect-Oriented Programming,这些用途可能会以任意方式改变应用程序的行为。此外,代理还可以修改应用程序外的代码,如JDK本身的代码。为了确保应用程序所有者批准代理的使用,JDK 5要求代理必须通过命令行选项-javaagent或-agentlib指定,并在启动时立即加载,这代表了应用程序所有者的明确授权。
可维护性与完整性
可维护性是指系统操作员在应用程序运行时监控、观察、调试和排查问题的能力。Java平台因其出色的可维护性而备受赞誉。为了支持可维护性工具,JDK 6引入了Attach API,该API并非Java平台的一部分,而是JDK提供的受支持的外部API。它允许具有适当操作系统权限的工具连接到正在运行的JVM(本地或远程),并与该JVM通信以观察和控制其操作。
然而,尽管在库和工具之间存在概念上的分离,某些库提供了依赖于代理的代码修改功能。例如,模拟库可能会重新定义应用程序类以绕过业务逻辑不变量,而白盒测试库可能会重新定义JDK类,以便始终允许对私有字段的反射。
不幸的是,一些库滥用了动态加载的代理,导致完整性的丧失。它们使用Attach API悄悄地连接到它们运行的JVM,并动态加载代理,实际上伪装成可维护性工具。这种滥用行为促使需要采取更强有力的措施来防止此类行为,并维护JVM的完整性。
未来展望
该提案旨在要求动态加载代理必须得到应用程序所有者的批准,从而使Java平台更接近默认完整性的长期愿景。在实际操作中,应用程序所有者必须通过命令行选项选择允许动态加载代理。
这一变化的影响将得到缓解,因为大多数现代服务器应用程序都设计为具有冗余性,因此可以根据需要重新启动单个节点并添加命令行选项。特殊情况(如必须永不停止维护的JVM)通常可以提前识别,以便从一开始就启用动态加载代理。
结论
这一变化将使Java生态系统实现默认完整性的愿景,而不会显著限制可维护性。这是确保JVM上运行的应用程序的安全性和可靠性的重要一步。该提案清楚地表明了OpenJDK在增强JVM完整性和确保Java应用程序安全运行方面的承诺。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用。你还可以使用@来通知其他用户。