Arthas ognl 命令完全指南:动态执行 OGNL 表达式深入解析 📅 发布时间:2026/9/19 14:12:37 👁 浏览次数: Arthas ognl 命令完全指南动态执行 OGNL 表达式深入解析【免费下载链接】arthasAlibaba Java Diagnostic Tool Arthas/Alibaba Java诊断利器Arthas项目地址: https://gitcode.com/gh_mirrors/ar/arthas本篇技术指南围绕 ArthasAlibaba Java Diagnostic Tool的ognl命令展开它是从 3.0.5 版本开始内置的在线执行 OGNL 表达式的调试利器常用于在不重启进程的前提下调用静态方法、读取静态字段、按指定 ClassLoader 加载并操作类也可以与watch、tt、trace等命令组合使用。读完本文你将掌握ognl的全部参数、典型实战用法以及其背后的表达式引擎与类加载解析原理能够在日常线上排障中直接上手。命令概述ognl命令用于在 Arthas 会话中执行一段 OGNL 表达式并把求值结果以结构化的方式打印出来。命令本身的定位非常简单——执行 ognl 表达式源码中的Summary(Execute ognl expression.)也印证了这一点见 OgnlCommand.java。它适用于以下典型场景调用某个类的静态方法例如输出一段信息到控制台读取某个类的静态字段例如排查一个随机数生成器的状态按指定 ClassLoader 解析并操作目标类Spring Boot 等框架下类由独立 ClassLoader 加载默认的 SystemClassLoader 无法直接找到执行多行表达式、把结果暂存到临时变量后一次性返回。参数说明参数名称参数说明express要执行的 OGNL 表达式必填命令行第一个参数[c:]执行表达式所使用的 ClassLoader 的 hashcode默认值是 SystemClassLoader[classLoaderClass:]指定执行表达式所使用的 ClassLoader 的 class name[x]结果对象的展开层次默认值 1对照 OgnlCommand.java 源码可以看到四个参数的落地方式express通过Argument(argName express, index 0, required true)声明是必填位置参数-c/--classLoader通过Option(shortName c, longName classLoader)声明接收 ClassLoader 的 hashcode--classLoaderClass通过Option(longName classLoaderClass)声明接收 ClassLoader 的类名-x/--expand通过Option(shortName x, longName expand)声明控制结果对象的展开层级默认值为 1。参数优先级与默认行为在 process 方法 中ClassLoader 的选取遵循如下逻辑若传入了-c hashcode则通过ClassLoaderUtils.getClassLoader(inst, hashCode)精确查找找不到时命令直接报错Can not find classloader with hashCode: ...若传入了--classLoaderClass className则通过ClassLoaderUtils.getClassLoaderByClassName(inst, classLoaderClass)按类名匹配恰好匹配到 1 个直接使用匹配到多个命令会列出所有匹配的 ClassLoader 信息并提示请使用-c classloader hash指定一个都没匹配到则报错Can not find classloader by class name: ...两者都未指定时默认使用ClassLoader.getSystemClassLoader()即 SystemClassLoader。也就是说-c的优先级最高、最精确--classLoaderClass适合“唯一实例”的 ClassLoader用起来更方便但存在多实例歧义两者都不传则只能在系统类加载器可见的类上做文章。快速上手示例调用静态函数$ ognl java.lang.Systemout.println(hello) null表达式语法为类全名静态成员。java.lang.Systemout定位到System类的out静态字段再调用其println方法。因为println返回void所以结果打印为null。获取静态类的静态字段$ ognl demo.MathGamerandom Random[ serialVersionUIDLong[3905348978240129619], seedAtomicLong[125451474443703], multiplierLong[25214903917], addendLong[11], maskLong[281474976710655], DOUBLE_UNITDouble[1.1102230246251565E-16], BadBoundString[bound must be positive], BadRangeString[bound must be greater than origin], BadSizeString[size must be non-negative], seedUniquifierAtomicLong[-3282039941672302964], nextNextGaussianDouble[0.0], haveNextNextGaussianBoolean[false], serialPersistentFieldsObjectStreamField[][isEmptyfalse;size3], unsafeUnsafe[sun.misc.Unsafe28ea5898], seedOffsetLong[24], ]默认展开层次为 1因此直接读取一个复杂对象时Arthas 会以类型[字段名值]的格式展示其内部结构继承自Object的静态字段如serialPersistentFields、unsafe也会一并呈现。若想看到更深层嵌套可以用-x增加展开层次例如ognl -x 2 demo.MathGamerandom对应源码中的new ObjectVO(value, expand)见 OgnlCommand.java。通过 hashcode 指定 ClassLoader对于 Spring Boot 这类把应用类放进自定义 ClassLoader 的场景直接用demo.MathGamerandom这种写法可能因类对 SystemClassLoader 不可见而失败。此时需要先确定目标 ClassLoader 的 hashcode再配合-c执行$ classloader -t -BootstrapClassLoader -jdk.internal.loader.ClassLoaders$PlatformClassLoader301ec38b -com.taobao.arthas.agent.ArthasClassloader472067c7 -jdk.internal.loader.ClassLoaders$AppClassLoader4b85612c -org.springframework.boot.loader.LaunchedURLClassLoader7f9a81e8 $ ognl -c 7f9a81e8 org.springframework.boot.SpringApplicationlogger Slf4jLocationAwareLog[ FQCNString[org.apache.commons.logging.LogAdapter$Slf4jLocationAwareLog], nameString[org.springframework.boot.SpringApplication], loggerLogger[Logger[org.springframework.boot.SpringApplication]], ]需要特别留意hashcode 是变化的对象地址相关每次启动都不同因此必须先在当前会话中用classloader -t查看最新的 ClassLoader 树提取目标 ClassLoader 的 hashcode 后再传入-c。通过 class name 指定 ClassLoader对于只有唯一实例的 ClassLoader用--classLoaderClass会更方便——它不需要每次去查 hashcode直接用类名即可$ ognl --classLoaderClass org.springframework.boot.loader.LaunchedURLClassLoader org.springframework.boot.SpringApplicationlogger Slf4jLocationAwareLog[ FQCNString[org.apache.commons.logging.LogAdapter$Slf4jLocationAwareLog], nameString[org.springframework.boot.SpringApplication], loggerLogger[Logger[org.springframework.boot.SpringApplication]], ]适用前提是目标 ClassLoader 在 JVM 中只有一个实例。若同名 ClassLoader 存在多个例如多个 Tomcat WebappClassLoader 并存命令会返回所有匹配实例的列表并要求改用-c hashcode精确定位这正是 OgnlCommand.java 中matchedClassLoaders.size() 1分支所处理的逻辑。执行多行表达式并返回 ListOGNL 支持#变量名值的临时变量赋值语法配合逗号分隔与末尾的{...}列表构造可以在一条命令里完成多次求值并聚合结果$ ognl #value1SystemgetProperty(java.home), #value2SystemgetProperty(java.runtime.name), {#value1, #value2} ArrayList[ String[/opt/java/8.0.181-zulu/jre], String[OpenJDK Runtime Environment], ]这里先用#value1、#value2两个临时变量分别保存两个系统属性再用{#value1, #value2}构造列表最终返回一个ArrayList。#前缀是 OGNL 上下文OgnlContext中变量的标准访问方式。底层原理ognl 命令是如何执行的了解命令背后的实现有助于理解参数语义和边界行为。表达式引擎 OgnlExpressognl 命令的求值引擎是 OgnlExpress.java它实现了Express接口构造时通过OgnlRuntime.setPropertyAccessor(Object.class, OBJECT_PROPERTY_ACCESSOR)注入自定义的属性访问器并创建一个OgnlContext其中MemberAccess使用DefaultMemberAccess(true)见下文get(String express)最终调用Ognl.getValue(express, context, bindObject)完成求值异常会被包装为ExpressException抛出由 OgnlCommand.process 捕获并提示查看$HOME/logs/arthas/arthas.log获取详细堆栈。私有成员访问控制ognl之所以能访问private/protected/ 包私有成员是因为 Arthas 自带的 DefaultMemberAccess.java 在DefaultMemberAccess(true)时对三类非公有成员全部放行并在访问前通过setAccessible(true)打开反射开关、结束后恢复原状态。类解析器与 ClassLoader 绑定当指定了-c或--classLoaderClass时ExpressFactory.unpooledExpress 会为选定的 ClassLoader 创建new OgnlExpress(new ClassLoaderClassResolver(classloader))——即用 ClassLoaderClassResolver.java 作为 OGNL 的ClassResolver所有类名引用都交给这个 ClassLoader 去loadClass这解释了为何能通过-c/--classLoaderClass访问 Spring Boot 内部类。类解析结果会缓存在ConcurrentHashMap中命中后不再重复加载。而默认情况下未指定 ClassLoader使用的是 CustomClassResolver.java它优先用线程上下文类加载器加载类解析失败时会回退尝试java.lang.前缀。strict 模式与属性修改限制ArthasObjectPropertyAccessor.java 重写了setPossibleProperty当全局strict选项开启时任何通过 OGNL 修改对象属性的操作都会抛出IllegalAccessError并提示全局严格模式信息用于防止在线上误改状态。因此ognl不仅能读也能写但在 strict 模式下写操作会被拦截。其他命令共用同一套 Express 框架ognl使用的Express/ExpressFactory框架同样服务于watch、tt、trace等命令的条件表达式求值见 WatchCommand.java、TimeTunnelCommand.java 等对Express的引用并且 Arthas MCP 服务也提供了对应的OgnlToolOgnlTool.java可将 ognl 能力以 MCP 工具形式暴露给 AI 编排。理解了 OGNL 语法后这些场景可以一并复用。使用注意事项ognl从 Arthas 3.0.5 版本开始提供使用前请确认你的 Arthas 版本不低于该版本执行目标类如果由非系统 ClassLoader 加载如 Spring Boot 的LaunchedURLClassLoader务必用-c或--classLoaderClass指定否则可能得到类找不到的错误-c的 hashcode 每次 JVM 运行都会变化应在当前会话中用classloader -t实时获取表达式中的$、#、等特殊字符在部分 shell 中需要转义或使用单引号包裹推荐按本文示例统一用单引号包裹整个表达式结果对象展开层次用-x控制默认 1 层过大的展开层数可能输出大量内容OGNL 特殊用法如#root、#this、集合投影/选择等可参考官方 OGNL 语言指南Arthas 文档也提供了 ognl 在线教程入口英文版见 site/docs/en/doc/ognl.md。总结ognl命令是 Arthas 中最灵活的“运行时求值器”默认挂在 SystemClassLoader 上可读可写、可展开多层对象面对自定义 ClassLoader 场景通过-c hashcode精确指定或--classLoaderClass按类名指定即可命中目标类。结合源码可以看到它的底层由OgnlExpressOGNL 3.x 引擎 自定义MemberAccess/ClassResolver/属性访问器驱动且与watch、tt、MCP 工具共享同一套表达式框架。掌握本命令你便可以在不改代码、不重启 JVM 的前提下对线上任意类做深入的运行时观测与诊断。【免费下载链接】arthasAlibaba Java Diagnostic Tool Arthas/Alibaba Java诊断利器Arthas项目地址: https://gitcode.com/gh_mirrors/ar/arthas创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考