本文主要參考慕課網(wǎng)若魚老師課程Java生產(chǎn)環(huán)境下性能監(jiān)控與調(diào)優(yōu)詳解
請支持正版,抵制盜版省容,維護每一位辛苦付出的人的合法權(quán)益冬三!
本章關(guān)鍵詞:BTrace匀油、攔截、注意事項
一勾笆、入門
1.做什么的肖抱?
- 可以在應(yīng)用程序不重啟郭计,不修改的情況下,正在運行的情況下,動態(tài)的修改字節(jié)碼倚喂,達到監(jiān)控調(diào)試的目的
- 可以動態(tài)的向目標應(yīng)用程序的字節(jié)碼注入追蹤代碼
- 用到的技術(shù)
JavaComplierApi、JVMTI馆铁、Agent榨为、Instrumentation+ASM
2.安裝
- 到官網(wǎng)中下載相應(yīng)版本
- 新建環(huán)境變量BTRACE_HOME,添加Path:%BTRACE_HOME%\bin
環(huán)境變量的添加請自行百度
- 兩種運行腳本方式
- JVisualVM中添加Btrace插件(參見上一章)啃勉,添加classpath
2.使用命令行btrace <pid> <trace_script>
3.使用詳解
-
代碼示例
btrace需要引入三個jar忽舟,就是下載的btrace程序中,build目錄下的三個
引入jar包
<!--btrace -->
<dependency>
<groupId>com.sun.btrace</groupId>
<artifactId>btrace-boot</artifactId>
<version>1.3.11</version>
<type>jar</type>
<scope>system</scope>
<systemPath>D:\btrace-bin-1.3.11\build\btrace-boot.jar</systemPath>
</dependency>
<dependency>
<groupId>com.sun.btrace</groupId>
<artifactId>btrace-agent</artifactId>
<version>1.3.11</version>
<type>jar</type>
<scope>system</scope>
<systemPath>D:\btrace-bin-1.3.11\build\btrace-agent.jar</systemPath>
</dependency>
<dependency>
<groupId>com.sun.btrace</groupId>
<artifactId>btrace-client</artifactId>
<version>1.3.11</version>
<type>jar</type>
<scope>system</scope>
<systemPath>D:\btrace-bin-1.3.11\build\btrace-client.jar</systemPath>
</dependency>
將要被攔截的代碼
package com.qinxianyun.monitor_tuning.chapter4;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
/**
* @author Qinxianyun
* @version V1.0
* @time 2018/7/21.12:50
* @description 演示btrace
*/
@RestController
@RequestMapping("ch4")
public class Ch4Controller {
@RequestMapping("/arg1")
public String arg1(@RequestParam("name")String name){
return "hello," + name;
}
}
btrace腳本(腳本和代碼沒有必要關(guān)聯(lián)性淮阐,腳本可以隨便寫在哪里叮阅,沒有必要寫在方法的一個項目里面)
package com.qinxianyun.monitor_tuning.chapter4;
import com.sun.btrace.AnyType;
import com.sun.btrace.BTraceUtils;
import com.sun.btrace.annotations.*;
@BTrace
public class PrintArgSimple {
@OnMethod(
clazz = "com.qinxianyun.monitor_tuning.chapter4.Ch4Controller",
method = "arg1",
location = @Location(Kind.ENTRY)
)
public static void anyRead(@ProbeClassName String pcn, @ProbeMethodName String pmn, AnyType[] args){
BTraceUtils.printArray(args);
BTraceUtils.println(pcn + "," + pmn);
BTraceUtils.println();
}
}
@OnMethod表示我們要攔截哪個類的哪個方法,在什么時候進行攔截
Kind.ENTRY表示在入口的時候攔截(也就是一進入方法的時候)
@param pcn 攔截方法類的類名
@param pmn 攔截方法的方法名
@param args 參數(shù)
-
進入到btrace腳本的目錄下
-
查看進程id
-
運行腳本文件
-
瀏覽器中輸入http://localhost:8080/ch4/arg1?name=qinxianyun
出現(xiàn)如下處理結(jié)果
-
Java VisualVM打開btrace(需要已經(jīng)安裝了插件泣特,詳情見上一章)
二浩姥、攔截構(gòu)造函數(shù)、同名函數(shù)
1.攔截方法(普通方法状您、構(gòu)造方法勒叠、同名方法)
- 普通方法 @OnMethod(clazz=" ",method=" ")
參考上面的例子
- 構(gòu)造函數(shù)@OnMethod(clazz=" ",method="<init>")
因為構(gòu)造函數(shù)在字節(jié)碼層面是叫init兜挨,所以用<init>
@RequestMapping("/constructor")
public User arg1(User user){
return user;
}
package com.qinxianyun.monitor_tuning.chapter2;
/**
* @author Qinxianyun
* @version V1.0
* @time 2018/7/15.14:52
* @description 用戶實體
*/
public class User {
private int id;
private String name;
public User(int id, String name) {
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
package com.qinxianyun.monitor_tuning.chapter4;
import com.sun.btrace.AnyType;
import com.sun.btrace.BTraceUtils;
import com.sun.btrace.annotations.BTrace;
import com.sun.btrace.annotations.OnMethod;
import com.sun.btrace.annotations.ProbeClassName;
import com.sun.btrace.annotations.ProbeMethodName;
@BTrace
public class PrintConstructor {
@OnMethod(
clazz = "com.qinxianyun.monitor_tuning.chapter2.User",
method = "<init>"
)
public static void anyRead(@ProbeClassName String pcn, @ProbeMethodName String pmn, AnyType[] args){
BTraceUtils.println(pcn + "," + pmn);
BTraceUtils.printArray(args);
BTraceUtils.println();
}
}
- 同名方法(用參數(shù)區(qū)分)
@RequestMapping("/same1")
public String same(@RequestParam("name")String name){
return "hello," + name;
}
@RequestMapping("/same2")
public String same(@RequestParam("name")String name,@RequestParam("id")int id){
return "hello," + name + "," +id;
}
package com.qinxianyun.monitor_tuning.chapter4;
import com.sun.btrace.AnyType;
import com.sun.btrace.BTraceUtils;
import com.sun.btrace.annotations.BTrace;
import com.sun.btrace.annotations.OnMethod;
import com.sun.btrace.annotations.ProbeClassName;
import com.sun.btrace.annotations.ProbeMethodName;
@BTrace
public class PrintSame {
@OnMethod(
clazz = "com.qinxianyun.monitor_tuning.chapter4.Ch4Controller",
method = "same"
)
public static void anyRead(@ProbeClassName String pcn, @ProbeMethodName String pmn, String name ,int id){
BTraceUtils.println(pcn + "," + pmn + "," + name + "," + id);
BTraceUtils.println();
}
}
攔截重載的方法,是根據(jù)參數(shù)的類型區(qū)分的眯分,腳本中的名字可以和代碼中參數(shù)名不一致
運行結(jié)果:
三拌汇、攔截返回值、異常行號
1.攔截時機
- Kind.ENTRY : 入口弊决,默認值
參考第一個例子
- Kind.RETURN : 返回
package com.qinxianyun.monitor_tuning.chapter4;
import com.sun.btrace.AnyType;
import com.sun.btrace.BTraceUtils;
import com.sun.btrace.annotations.*;
@BTrace
public class PrintReturn {
@OnMethod(
clazz = "com.qinxianyun.monitor_tuning.chapter4.Ch4Controller",
method = "arg1",
location = @Location(Kind.RETURN)
)
public static void anyRead(@ProbeClassName String pcn, @ProbeMethodName String pmn, @Return AnyType result){
BTraceUtils.println(pcn + "," + pmn + "," + result);
BTraceUtils.println();
}
}
- Kind.THROW : 異常
package com.qinxianyun.monitor_tuning.chapter4;
import com.sun.btrace.BTraceUtils;
import com.sun.btrace.annotations.*;
@BTrace
public class PrintOnThrow {
@TLS
static Throwable currentException;
@OnMethod(
clazz = "java.lang.Throwable",
method = "<init>"
)
public static void onthrow(@Self Throwable self){//new Throwable()
currentException = self;
}
@OnMethod(
clazz = "java.lang.Throwable",
method = "<init>"
)
public static void onthrow1(@Self Throwable self,String s){//new Throwable(String msg)
currentException = self;
}
@OnMethod(
clazz = "java.lang.Throwable",
method = "<init>"
)
public static void onthrow1(@Self Throwable self,String s,Throwable cause){//new Throwable(String msg,Throwable cause)
currentException = self;
}
@OnMethod(
clazz = "java.lang.Throwable",
method = "<init>"
)
public static void onthrow2(@Self Throwable self,Throwable cause){//new Throwable(Throwable cause)
currentException = self;
}
@OnMethod(
clazz = "java.lang.Throwable",
method = "<init>",
location = @Location(Kind.RETURN)
)
public static void onthrowreturn(){
if (currentException != null){
BTraceUtils.Threads.jstack(currentException);
BTraceUtils.println("========================");
currentException = null;
}
}
}
- Kind.Line :行
package com.qinxianyun.monitor_tuning.chapter4;
import com.sun.btrace.BTraceUtils;
import com.sun.btrace.annotations.*;
@BTrace
public class PrintLine {
@OnMethod(
clazz = "com.qinxianyun.monitor_tuning.chapter4.Ch4Controller",
location = @Location(value = Kind.LINE,line = 41)
)
public static void anyRead(@ProbeClassName String pcn,@ProbeMethodName String pmn,int line){
BTraceUtils.println(pcn + "," + pmn + "," + line);
BTraceUtils.println();
}
}
四噪舀、攔截復(fù)雜參數(shù)、環(huán)境變量飘诗、正則匹配攔截
1.攔截this与倡、入?yún)ⅰ⒎祷?/h4>
- this:@Self
- 入?yún)ⅲ嚎梢杂肁nyType昆稿,也可以用真實類型纺座,同名的用真實的
- 返回:@Return
2.獲取對象的值
- 簡單類型:直接獲取
- 復(fù)雜類型:反射,類名+屬性名
package com.qinxianyun.monitor_tuning.chapter4;
import com.qinxianyun.monitor_tuning.chapter2.User;
import com.sun.btrace.BTraceUtils;
import com.sun.btrace.annotations.*;
import java.lang.reflect.Field;
@BTrace
public class PrintArgComplex {
@OnMethod(
clazz = "com.qinxianyun.monitor_tuning.chapter4.Ch4Controller",
method = "arg2",
location = @Location(Kind.ENTRY)
)
public static void anyRead(@ProbeClassName String pcn, @ProbeMethodName String pmn, User user){
BTraceUtils.printFields(user);
Field field2 = BTraceUtils.field("com.qinxianyun.monitor_tuning.chapter2.User","name");
BTraceUtils.println(BTraceUtils.get(field2,user));
BTraceUtils.println(pcn + "," + pmn);
BTraceUtils.println();
}
}
注意:
引用的需要加上-cp
3.正則表達式
- 攔截任意方法
package com.qinxianyun.monitor_tuning.chapter4;
import com.sun.btrace.BTraceUtils;
import com.sun.btrace.annotations.*;
@BTrace
public class PrintRegex {
@OnMethod(
clazz = "com.qinxianyun.monitor_tuning.chapter4.Ch4Controller",
method = "/.*/"
)
public static void anyRead(@ProbeClassName String pcn, @ProbeMethodName String pmn){
BTraceUtils.println(pcn + "," + pmn);
BTraceUtils.println();
}
}
4.打印環(huán)境變量
- 打印(輸出類似Jinfo命令)
package com.qinxianyun.monitor_tuning.chapter4;
import com.sun.btrace.BTraceUtils;
import com.sun.btrace.annotations.BTrace;
@BTrace
public class PrintJinfo {
static {
BTraceUtils.println("System Properties:");
BTraceUtils.printProperties();
BTraceUtils.println("VM Flags:");
BTraceUtils.printVmArguments();
BTraceUtils.println("OS Enviroment:");
BTraceUtils.printEnv();
BTraceUtils.exit();
}
}
-
輸出結(jié)果
注意事項:
1.默認只能本地運行
2.生產(chǎn)環(huán)境下可以使用溉潭,但是被修改的字節(jié)碼不會被還原(即使btrace退出)
因此比驻,腳本中不要有太耗系統(tǒng)資源的東西,否則會影響服務(wù)器岛抄。
package com.qinxianyun.monitor_tuning.chapter4;
import com.qinxianyun.monitor_tuning.chapter2.User;
import com.sun.btrace.BTraceUtils;
import com.sun.btrace.annotations.*;
import java.lang.reflect.Field;
@BTrace
public class PrintArgComplex {
@OnMethod(
clazz = "com.qinxianyun.monitor_tuning.chapter4.Ch4Controller",
method = "arg2",
location = @Location(Kind.ENTRY)
)
public static void anyRead(@ProbeClassName String pcn, @ProbeMethodName String pmn, User user){
BTraceUtils.printFields(user);
Field field2 = BTraceUtils.field("com.qinxianyun.monitor_tuning.chapter2.User","name");
BTraceUtils.println(BTraceUtils.get(field2,user));
BTraceUtils.println(pcn + "," + pmn);
BTraceUtils.println();
}
}
引用的需要加上-cp
package com.qinxianyun.monitor_tuning.chapter4;
import com.sun.btrace.BTraceUtils;
import com.sun.btrace.annotations.*;
@BTrace
public class PrintRegex {
@OnMethod(
clazz = "com.qinxianyun.monitor_tuning.chapter4.Ch4Controller",
method = "/.*/"
)
public static void anyRead(@ProbeClassName String pcn, @ProbeMethodName String pmn){
BTraceUtils.println(pcn + "," + pmn);
BTraceUtils.println();
}
}
package com.qinxianyun.monitor_tuning.chapter4;
import com.sun.btrace.BTraceUtils;
import com.sun.btrace.annotations.BTrace;
@BTrace
public class PrintJinfo {
static {
BTraceUtils.println("System Properties:");
BTraceUtils.printProperties();
BTraceUtils.println("VM Flags:");
BTraceUtils.printVmArguments();
BTraceUtils.println("OS Enviroment:");
BTraceUtils.printEnv();
BTraceUtils.exit();
}
}
輸出結(jié)果
注意事項:
1.默認只能本地運行
2.生產(chǎn)環(huán)境下可以使用溉潭,但是被修改的字節(jié)碼不會被還原(即使btrace退出)
因此比驻,腳本中不要有太耗系統(tǒng)資源的東西,否則會影響服務(wù)器岛抄。