测试业务类
测试接口
package cn.freemethod.business;
public interface SumInter {
long sum(int num);
}
测试实现类
package cn.freemethod.business;
import javax.annotation.Resource;
@Resource
public class GSumInterImpl implements SumInter{
@Override
public long sum(int num) {
if(num % 2 == 0)
return (1 + num) * (num / 2);
else
return (1 + num) * (num - 1)/2 + (num + 1) /2;
}
}
package cn.freemethod.business;
import javax.annotation.Resource;
public class SumInterImpl implements SumInter{
@Override
public long sum(int num) {
int sum = 0;
for(int i =0 ;i<num;i++){
sum += i;
}
return sum;
}
@Resource
public int doSomething(String arg1,Integer arg2){
return arg1.hashCode() + arg2;
}
}
启动类
package cn.freemethod.business;
import java.util.Scanner;
public class SumStart {
public static void main(String[] args) {
GSumInterImpl gSumInter = new GSumInterImpl();
SumInterImpl sumInter = new SumInterImpl();
final Scanner scanner = new Scanner(System.in);
scanner.nextLine();
gSumInter.sum(10000);
sumInter.sum(10000);
sumInter.doSomething("hello",10);
scanner.nextLine();
}
}
这里使用scanner.nextLine();是为了等脚本启动好了手动控制执行。
BTrace脚本
package cn.freemethod.btracet;
import com.sun.btrace.AnyType;
import com.sun.btrace.annotations.*;
import static com.sun.btrace.BTraceUtils.Sys.Env.printEnv;
import static com.sun.btrace.BTraceUtils.Sys.Env.printProperties;
import static com.sun.btrace.BTraceUtils.Sys.Memory.heapUsage;
import static com.sun.btrace.BTraceUtils.Sys.Memory.nonHeapUsage;
import static com.sun.btrace.BTraceUtils.Sys.VM.printVmArguments;
import static com.sun.btrace.BTraceUtils.println;
@BTrace
public class OnMethodTrace {
static{
println("--printVmArguments()--");
printVmArguments();
println("--printProperties()--");
printProperties();
println("--printEnv()--");
printEnv();
println("--heapUsage()--");
println(heapUsage());
println("--nonHeapUsage()--");
println(nonHeapUsage());
// exit();
}
// @OnMethod(clazz="/java\\.util\\..*/",method="/.*/")
@OnMethod(clazz="+java.util.Map",method="/.*/")
public static void utilMethod(@ProbeClassName String probeClass, @ProbeMethodName String probeMethod) {
println("utilMethod:" + probeClass + "." + probeMethod);
}
@OnMethod(clazz = "+cn.freemethod.business.SumInter", method = "sum", location = @Location(Kind.RETURN))
public static void onSum(@ProbeClassName String probeClass, @ProbeMethodName String probeMethod,@Return long sum, @Duration long duration){
println("onSum:"+ probeClass + "." + probeMethod + "_" + sum + "_" + duration);
}
@OnMethod(clazz = "cn.freemethod.business.SumInterImpl", method = "@javax.annotation.Resource", location = @Location(value = Kind.RETURN))
public static void onAnnotationResourceMethod(@Self Object self, String arg1, Integer arg2, @Return AnyType result){
println("onAnnotationResourceMethod:" + arg1 + "_" + arg2 + "_" + result);
}
@OnMethod(clazz = "@javax.annotation.Resource", location = @Location(value = Kind.LINE, line = 10))
public static void onLine(int line) {
println("onLine reached line:10 " + line);
}
}
执行方式是在BTrace下载下载BTrace,解压在bin目录下执行:
btrace pid OnMethodTrace.java
脚本要拷贝到BTrace的bin目录下,否则就使用绝对路径。pid可以通过jps命令获取到。
更详细的内容可以参考BTrace使用
我们可以看到OnMethodTrace脚本中的static块部分,这一部分主要是打印jvm相关信息的,其实在实际中可能很少用,因为这些都可以jstat,jmap等工具获取到。
所有我们还是来看一下其他的:
// @OnMethod(clazz="/java\\.util\\..*/",method="/.*/")
@OnMethod(clazz="+java.util.Map",method="/.*/")
@OnMethod注解是用来拦截指定方法的,clazz属性是指定类,可以使用全限定名或者正则表达式,也可以使用接口(前面添加"+")。method可以是名字也可以是正则表达式。匹配的时候尽量让拦截的方法范围小一些,避免出现性能问题。
@ProbeClassName是注入被拦截方法所在的类的名字 @ProbeMethodName是注入被拦截方法的名字 @Return 是注入拦截时间 @Duration 是注入方法执行时间(单位是纳秒,要除以1000000才是毫秒,location必须是Kind.RETURN) @Self是注入调用被拦截方法的实例(this)
还可以注入被拦截方法的参数,我们看下面这个:
public static void onAnnotationResourceMethod(@Self Object self, String arg1, Integer arg2, @Return AnyType result)
注意:定义一定要按顺序,必须是@Self,参数1,参数2...,@Return
参数也可以使用AnyType[] args来定义,返回值也可以使用AnyType。
@OnMethod(clazz = "@javax.annotation.Resource", location = @Location(value = Kind.LINE, line = 10))
line是指定执行到指定行的时候执行,line=-1的时候是每行都会执行,加参数int line 注入当前行数
输出的内容比较多,大概就像是下面的样子: