原文链接:SkyWalking中是如何统计方法调用时间的 – 编程屋
1 前言
SkyWalKing中对每个方法和调用时间都进行了统计。那么他是如何实现的呢?
其实他是用了ByteBuddy和Java agent技术来统计方法的调用时长。
1.1 javaagent我在上一篇博客中已经提到过链接地址:SkyWalking中javaagent的使用原理 – 编程屋
byteBuddy框架致力于解决字节码操作和instrumentaton API的复杂性。ByteBuddy所声称目标是先将显示的字节码操作隐藏在一个类型安全的领域的特定语言背后。ByteBuddy提供了额外的API来生成Javaagent。
2.代码实现
有关项目结构:
2.1 首先在java_agent_demo项目中加入byteButty有关依赖(注意:该工程pom文件中除了这两个依赖,还有相关插件,这里不一一展示。可以在上篇博客找到。)
<dependencies>
<dependency>
<groupId>net.bytebuddy</groupId>
<artifactId>byte-buddy</artifactId>
<version>1.9.16</version>
</dependency>
<dependency>
<groupId>net.bytebuddy</groupId>
<artifactId>byte-buddy-agent</artifactId>
<version>1.9.16</version>
</dependency>
</dependencies>
2.2 PreMainClass类
public class PreMainClass {
public static void premain(String agentparam, Instrumentation inst){
AgentBuilder.Transformer transformer = new AgentBuilder.Transformer() {
@Override
public DynamicType.Builder<?> transform(DynamicType.Builder<?> builder, TypeDescription typeDescription, ClassLoader classLoader, JavaModule module) {
//method指定哪些方法需要被拦截 ElementMatchers.any()指定了所有方法
//intercept声明的拦截器 MyIntercept自己声明拦截器的类
return builder.method(ElementMatchers.any()).intercept(MethodDelegation.to(MyIntercept.class));
}
};
// type指定了agent拦截的包名 以 com.agent作为前缀
//指定了transform 将配置安装到了Instrumentation中
new AgentBuilder.Default().type(ElementMatchers.nameStartsWith("com.agent"))
.transform(transformer).installOn(inst);
}
}
自己定义的MyIntercept拦截类:
public class MyIntercept {
/**
* 因为我们方法是在运行过程中被拦截的,所以加上@RuntimeType注解
* @param method
* @param callable
* @return
* @throws Exception
*/
@RuntimeType
public static Object incercept(@Origin Method method,
@SuperCall Callable<?> callable) throws Exception {
long start = System.currentTimeMillis();
try {
return callable.call();
}finally {
System.out.println(method.getName()+":"+(System.currentTimeMillis() - start+"ms"));
}
}
}
一定要加上@RunTimeType注解。全部完成之后,记得打包,并且找到生成jar包的地址,后面会用到。
以上只是部分内容,为了维护方便,本文已迁移到新地址:
SkyWalking中是如何统计方法调用时间的 – 编程屋