Arthas的高级操作 – Ognl表达式

Java基础

浏览数:261

2019-10-3

Arthas的一个很重要的应用场景,就是查看运行时的数据,但有时需要动态的查看数据,或者数据过多,需要动态筛选,比较复杂的规则就需要靠OGNL了。

下面介绍一些常用的arthas中ognl的操作,测试代码如下,springboot工程:

@RequestMapping("send")
public String send(HttpServletRequest request, HttpServletResponse response){
    return doSend(createUserList(),false);
}

public String doSend(List<User> userList,boolean flag){
    System.out.println("doSend");
    return "success";
}

private List<User> createUserList(){
    List<User> userList = new ArrayList<>();
    for (long i = 0; i < 10; i++) {
        User user = new User();
        user.setId(i);
        user.setUsername("u"+i);
        userList.add(user);
    }
    return userList;
}

class User {
    private String username;
    private Long id;
    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    private String convert(){
        return id+"_"+username;
    }
}

查看第N个参数

watch com.example.httpclientdemo.HttpclientDemoApplication send 'params[0]'
Press Q or Ctrl+C to abort.
Affect(class-cnt:2 , method-cnt:1) cost in 45 ms.
ts=2019-09-26 15:13:38; [cost=0.267515ms] result=@RequestFacade[
    request=@Request[org.apache.catalina.connector.Request@5b518aa4],
    sm=@StringManager[org.apache.tomcat.util.res.StringManager@6ffbca2e],
]

查看参数的某个属性

watch com.example.httpclientdemo.HttpclientDemoApplication send 'params[0].class.name'
Press Q or Ctrl+C to abort.
Affect(class-cnt:2 , method-cnt:1) cost in 50 ms.
ts=2019-09-26 15:15:17; [cost=0.252717ms] result=@String[org.apache.catalina.connector.RequestFacade]

查看某个参数的个某个方法的返回值

watch com.example.httpclientdemo.HttpclientDemoApplication send 'params[0].getMethod()'
Press Q or Ctrl+C to abort.
Affect(class-cnt:2 , method-cnt:1) cost in 55 ms.
ts=2019-09-26 15:15:49; [cost=0.289059ms] result=@String[GET]

投影(Across)

简单的说,就是查看集合中元素的属性或者方法返回值,和lambda里的map很像

watch com.example.httpclientdemo.HttpclientDemoApplication doSend 'params[0].{#this.username}' -b -x 2
Press Q or Ctrl+C to abort.
Affect(class-cnt:2 , method-cnt:1) cost in 28 ms.
ts=2019-09-26 15:19:49; [cost=0.006187ms] result=@ArrayList[
    @String[u0],
    @String[u1],
    @String[u2],
    @String[u3],
    @String[u4],
    @String[u5],
    @String[u6],
    @String[u7],
    @String[u8],
    @String[u9],
]

还可以在投影中调用方法

watch com.example.httpclientdemo.HttpclientDemoApplication doSend 'params[0].{#this.convert()}'
Press Q or Ctrl+C to abort.
Affect(class-cnt:2 , method-cnt:1) cost in 83 ms.
ts=2019-09-26 15:30:04; [cost=0.349277ms] result=@ArrayList[
    @String[0_u0],
    @String[1_u1],
    @String[2_u2],
    @String[3_u3],
    @String[4_u4],
    @String[5_u5],
    @String[6_u6],
    @String[7_u7],
    @String[8_u8],
    @String[9_u9],
]

在观察表达式里过滤

watch com.example.httpclientdemo.HttpclientDemoApplication doSend 'params[0].{? #this.id > 8}' -b -x 2
Press Q or Ctrl+C to abort.
Affect(class-cnt:2 , method-cnt:1) cost in 33 ms.
ts=2019-09-26 15:23:10; [cost=0.006812ms] result=@ArrayList[
    @User[
        username=@String[u9],
        id=@Long[9],
    ],
]

过滤后计数

 watch com.example.httpclientdemo.HttpclientDemoApplication doSend 'params[0].{? #this.username.endsWith("9")}.size()'
Press Q or Ctrl+C to abort.
Affect(class-cnt:2 , method-cnt:1) cost in 27 ms.
ts=2019-09-26 15:33:12; [cost=0.165327ms] result=@Integer[1]

这里需要分清楚,在条件表达式里写过滤条件和直接在观察表达式里写过滤条件的区别:

  • 条件表达式过滤的是一次调用,判断该次调用能否返回
  • 观察表达式里的过滤,过滤的是该次调用的数据,不管怎么写,该次调用一定返回

当然也可以在条件表达式里写Ongl,效果是类似的:

 watch com.example.httpclientdemo.HttpclientDemoApplication doSend 'params[0].{#this.username}' 'params[0].{? #this.id>7}.size()>0'
Press Q or Ctrl+C to abort.
Affect(class-cnt:2 , method-cnt:1) cost in 39 ms.
ts=2019-09-26 15:45:12; [cost=0.19965ms] result=@ArrayList[
    @String[u0],
    @String[u1],
    @String[u2],
    @String[u3],
    @String[u4],
    @String[u5],
    @String[u6],
    @String[u7],
    @String[u8],
    @String[u9],
]

子表达式计算

watch com.example.httpclientdemo.HttpclientDemoApplication doSend 'params[0].size().(#this>5? 20+#this:10+#this)'
Press Q or Ctrl+C to abort.
Affect(class-cnt:2 , method-cnt:1) cost in 52 ms.
ts=2019-09-26 15:58:36; [cost=0.179407ms] result=@Integer[30]

选择第一个匹配项

watch com.example.httpclientdemo.HttpclientDemoApplication doSend 'params[0].{^#this.username.startsWith("u")}' -b -x 2
Press Q or Ctrl+C to abort.
Affect(class-cnt:2 , method-cnt:1) cost in 141 ms.
ts=2019-09-26 17:18:01; [cost=0.41405ms] result=@ArrayList[
    @User[
        username=@String[u0],
        id=@Long[0],
        this$0=@HttpclientDemoApplication$$EnhancerBySpringCGLIB$$10ddbd36[com.example.httpclientdemo.HttpclientDemoApplication$$EnhancerBySpringCGLIB$$10ddbd36@d5d5b7f],
    ],
]

选择最后一个匹配项

watch com.example.httpclientdemo.HttpclientDemoApplication doSend 'params[0].{$#this.username.startsWith("u")}' -b -x 2
Press Q or Ctrl+C to abort.
Affect(class-cnt:2 , method-cnt:1) cost in 84 ms.
ts=2019-09-26 17:18:32; [cost=0.036367ms] result=@ArrayList[
    @User[
        username=@String[u9],
        id=@Long[9],
        this$0=@HttpclientDemoApplication$$EnhancerBySpringCGLIB$$10ddbd36[com.example.httpclientdemo.HttpclientDemoApplication$$EnhancerBySpringCGLIB$$10ddbd36@d5d5b7f],
    ],
]

调用静态方法

watch 时调用静态方法
watch com.example.httpclientdemo.HttpclientDemoApplication doSend '@java.lang.Thread@currentThread()'
Press Q or Ctrl+C to abort.
Affect(class-cnt:2 , method-cnt:1) cost in 31 ms.
ts=2019-09-26 17:20:29; [cost=0.13471ms] result=@TaskThread[
    log=@DirectJDKLog[org.apache.juli.logging.DirectJDKLog@2f1ab57a],
    creationTime=@Long[1569484802267],
]

ognl 调用静态方法
注意:ognl会受classloader的限制,如果在tomcat之类的环境下,会找不到对应的类

ognl '@com.example.httpclientdemo.SpringApplicationContextHolder@getBean("your bean name")'

ognl获取静态属性

ognl '@com.example.httpclientdemo.SpringApplicationContextHolder@isDestroyed'

getstat获取静态属性

getstatic com.example.httpclientdemo.SpringApplicationContextHolder applicationContext

作者:空无