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