-
Notifications
You must be signed in to change notification settings - Fork 7.6k
表达式支持使用qlexpress4.0 #2978
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
表达式支持使用qlexpress4.0 #2978
Conversation
# Conflicts: # core/pom.xml # pom.xml
缺少测试,有冲突需要解决。 |
# Conflicts: # core/src/main/java/com/taobao/arthas/core/GlobalOptions.java # core/src/test/java/com/taobao/arthas/core/command/express/OgnlTest.java
* 是否切换使用表达式ognl/qlexpress开关 | ||
*/ | ||
@Option(level = 1, | ||
name = "express-type", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
是不是可以考虑短一点,比如就缩写成 el(expression language)
* qlexpress使用参数 | ||
*/ | ||
@Option(level = 1, | ||
name = "qlexpress-config", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
这么复杂的东西暂时没必要交给用户设置吧。我们直接给一个最推荐的就行了,没必要暴露给用户,毕竟这个场景比较单一,给个通用配置就够了
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok
public QLExpress(ClassSupplier classResolver) { | ||
initQLExpress(classResolver); | ||
initConfig(); | ||
initContext(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
其实这三个函数就是分别初始化三个成员变量,下面这种写法可能更加清晰:
this.expressRunner = initQLExpress(classResolver);
this.qlOptions = initConfig();
this.qlGlobalContext = initContext();
尽量不要使用有副作用的函数
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fix
|
||
@Override | ||
public Express bind(String name, Object value) { | ||
qlGlobalContext.put(name, value); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
个人觉得在 put 的时候加上 "#" 前缀,要比 get 的时候 replace 要好。这样 context 的逻辑更加简单纯粹。replace 可能会导致改变不该改变的字符。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok
|
||
public void clear() { | ||
context.clear(); | ||
this.context.put("reflectLoader",reflectLoader); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
这里的用处是?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
每次bind之前调用清理现成参数
if ((this.reflectLoader != null) && (this.object != null) && !variableName.startsWith("#")) { | ||
return this.reflectLoader.loadField(this.object, variableName, true, PureErrReporter.INSTANCE); | ||
} | ||
String newVariableName = variableName.replace("#",""); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
个人觉得在 put 的时候加上前缀,比 get 的时候隐藏一个 # 替换逻辑要更好
@Override | ||
public Value get(Map<String, Object> attachments, String variableName) { | ||
if ((this.reflectLoader != null) && (this.object != null) && !variableName.startsWith("#")) { | ||
return this.reflectLoader.loadField(this.object, variableName, true, PureErrReporter.INSTANCE); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
这个 api 有点底层,可以考虑继承 ObjectFieldExpressContext,然后额外加一个 map 功能,而不是直接调用 reflectLoader。或者我直接在 Express4Runner 上开个 api
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
待讨论点
+ " ognl -c 5d113a51 '@com.taobao.arthas.core.GlobalOptions@isDump' \n" | ||
+ Constants.WIKI + Constants.WIKI_HOME + "ognl\n" | ||
+ " https://commons.apache.org/proper/commons-ognl/language-guide.html") | ||
+ " ognl '@[email protected](\"hello \\u4e2d\\u6587\")' \n" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
是不是也得有一个类似 ognl 这样的纯执行 qlexpress 表达式的命令
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
待讨论点
site/docs/en/doc/options.md
Outdated
| verbose | false | This option enables print verbose information | | ||
| strict | true | whether to enable strict mode | | ||
|
||
| express-type | ognl | Option to use ognl/qlexpress in commands, default ognl, can change to qlexpress | |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
上次讨论的这个选项的名称是否考虑短一点,比如叫做 el,这样避免用户在使用 qle 时敲的命令太长
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
另外文档中是不是得有一些例子
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
然后 qlexpress 也不用输全名,就写 qle 即可
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
例子可以加一些有特色的,能解决具体问题的,比如复杂对象构造,list新建等等
可以再举一个复杂对象构造的例子。 |
# Conflicts: # core/src/main/java/com/taobao/arthas/core/GlobalOptions.java
# Conflicts: # core/src/main/java/com/taobao/arthas/core/GlobalOptions.java
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR introduces support for QLExpress 4.0 as an alternative expression engine to OGNL in Arthas. The implementation adds a new qlexpress
command and allows users to switch the default expression language through a global option.
Key changes:
- Added QLExpress 4.0 dependency and integration classes
- Implemented new
qlexpress
command with similar functionality to the existingognl
command - Added global option
el
to switch between OGNL and QLExpress engines - Updated documentation to reflect the new expression language options
Reviewed Changes
Copilot reviewed 18 out of 18 changed files in this pull request and generated 4 comments.
Show a summary per file
File | Description |
---|---|
pom.xml | Added QLExpress 4.0 dependency |
core/pom.xml | Added QLExpress 4.0 dependency with duplicate OGNL entry |
GlobalOptions.java | Added el option to switch expression languages |
ExpressFactory.java | Modified to support both OGNL and QLExpress based on global option |
QLExpressCommand.java | New command implementation for QLExpress functionality |
QLExpress*.java | Supporting classes for QLExpress integration |
BuiltinCommandPack.java | Registered new QLExpress command |
site/docs/* | Updated documentation for new expression language option |
Comments suppressed due to low confidence (1)
site/docs/en/doc/options.md:10
- [nitpick] The table formatting appears inconsistent. The original formatting with spaces should be maintained for better readability:
| ---------------------- | ------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
|------------------------| ------------- |-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
core/pom.xml
Outdated
<dependency> | ||
<groupId>ognl</groupId> | ||
<artifactId>ognl</artifactId> | ||
</dependency> |
Copilot
AI
Aug 10, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There appears to be a duplicate OGNL dependency declaration. The OGNL dependency is already declared at line 211-213, making this additional declaration redundant.
<dependency> | |
<groupId>ognl</groupId> | |
<artifactId>ognl</artifactId> | |
</dependency> |
Copilot uses AI. Check for mistakes.
import com.taobao.arthas.core.command.express.ExpressFactory; | ||
import com.taobao.arthas.core.command.model.ClassLoaderVO; | ||
import com.taobao.arthas.core.command.model.ObjectVO; | ||
import com.taobao.arthas.core.command.model.OgnlModel; |
Copilot
AI
Aug 10, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The import for OgnlModel is unused in this class. Since this class uses QLExpressModel instead, this import should be removed.
import com.taobao.arthas.core.command.model.OgnlModel; |
Copilot uses AI. Check for mistakes.
import com.taobao.arthas.core.GlobalOptions; | ||
import com.taobao.arthas.core.advisor.Advice; | ||
import com.taobao.arthas.core.command.model.ExpressTypeEnum; | ||
import ognl.OgnlException; |
Copilot
AI
Aug 10, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The import for OgnlException appears incorrect for a QLExpress test class. The test methods declare throwing OgnlException but should likely throw ExpressException instead.
import ognl.OgnlException; |
Copilot uses AI. Check for mistakes.
Co-authored-by: Copilot <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
背景链接:
Proposal: 表达式体验优化与引擎更换 #2849
改动实现:
新增了qlexpress自己的command,命令名称 qlexpress
参数说明
使用参考:
$ qlexpress 'java.lang.System.out.println("hello~")'
通过 hashcode 指定 ClassLoader:
$classloader -t +-BootstrapClassLoader +-jdk.internal.loader.ClassLoaders$PlatformClassLoader@301ec38b +-com.taobao.arthas.agent.ArthasClassloader@472067c7 +-jdk.internal.loader.ClassLoaders$AppClassLoader@4b85612c +-org.springframework.boot.loader.LaunchedURLClassLoader@7f9a81e8
$ qlexpress -c 7f9a81e8 org.springframework.boot.SpringApplication.logger
注意 hashcode 是变化的,需要先查看当前的 ClassLoader 信息,提取对应 ClassLoader 的 hashcode。
对于只有唯一实例的 ClassLoader 可以通过 class name 指定,使用起来更加方便:
$ qlexpress --classLoaderClass org.springframework.boot.loader.LaunchedURLClassLoader org.springframework.boot.SpringApplication.logger
和ognl相比语法的区别
option中新增"el"属性配置,支持切换ognl语法为qlexpress

使用语言切换成qlexpress
$ option el qlexpress
对于观察表达式,获取观测数据的方法:
OGNL:
{params, target, returnObj}
QLEXPRESS:
[params, target, returnObj]
常用用法举例
OGNL语法
$ watch demo.MathGame primeFactors '{params, returnObj}' '#cost>200' -x 2
QLEXPRESS4语法
$ watch demo.MathGame primeFactors '[params, returnOb]' 'cost>200' -x 2
更多qlexpress4.0语法链接
https://github.com/alibaba/QLExpress/tree/v4.0.0-beta.1