摘要:一网上关于的介绍很多,请找度娘和谷兄。唯一提的一点是字节码注入比较好用的是,封装度很高,使用简单。二代码样例以下为关键代码样例,可以依样画瓢自行改造。加入栈实战营知识星球,参与讨论,更多实战代码分享,不就是几斤苹果,几个荣耀道具的事吗
一、Javaagent
网上关于Javaagent的介绍很多,请找度娘和谷兄。唯一提的一点是字节码注入比较好用的是bytebuddy,封装度很高,使用简单。
二、代码样例以下为关键代码样例,可以依样画瓢自行改造。
1.编写agent入口
package com.javashizhan.trace;
import static net.bytebuddy.matcher.ElementMatchers.isInterface;
import static net.bytebuddy.matcher.ElementMatchers.isSetter;
import static net.bytebuddy.matcher.ElementMatchers.nameContainsIgnoreCase;
import static net.bytebuddy.matcher.ElementMatchers.nameStartsWithIgnoreCase;
import static net.bytebuddy.matcher.ElementMatchers.not;
import java.lang.instrument.Instrumentation;
import com.javashizhan.trace.interceptor.AbstractJunction;
import com.javashizhan.trace.interceptor.ProtectiveShieldMatcher;
import com.javashizhan.trace.interceptor.TraceInterceptor;
import net.bytebuddy.agent.builder.AgentBuilder;
import net.bytebuddy.description.NamedElement;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.implementation.MethodDelegation;
import net.bytebuddy.matcher.ElementMatcher;
import net.bytebuddy.matcher.ElementMatchers;
public class TraceAgent {
public static void premain(String arguments, Instrumentation instrumentation) {
new AgentBuilder.Default()
.type(buildMatch())
.transform((builder, type, classLoader, module) ->
builder.method(ElementMatchers.any())
.intercept(MethodDelegation.to(TraceInterceptor.class)) // 拦截器
).installOn(instrumentation);
}
public static ElementMatcher super TypeDescription> buildMatch() {
ElementMatcher.Junction judge = new AbstractJunction() {
@Override
public boolean matches(NamedElement target) {
return true;
}
};
judge = judge.and(not(isInterface())).and(not(isSetter()))
.and(nameStartsWithIgnoreCase("io.spring"))
.and(not(nameContainsIgnoreCase("util")))
.and(not(nameContainsIgnoreCase("interceptor")));
judge = judge.and(not(isSetter()));
return new ProtectiveShieldMatcher(judge);
}
}
2.拦截器类TraceInterceptor.java
package com.javashizhan.trace.interceptor;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.List;
import java.util.concurrent.Callable;
import com.javashizhan.trace.domain.CallMethod;
import com.javashizhan.trace.TraceWrapper;
import com.javashizhan.trace.collector.DBCollector;
import com.javashizhan.trace.domain.Trace;
import com.javashizhan.trace.domain.TraceRecord;
import net.bytebuddy.implementation.bind.annotation.Origin;
import net.bytebuddy.implementation.bind.annotation.RuntimeType;
import net.bytebuddy.implementation.bind.annotation.SuperCall;
public class TraceInterceptor {
@RuntimeType
public static Object intercept(@Origin Method method,
@SuperCall Callable> callable) throws Exception {
before(method);
try {
return callable.call();
} finally {
after();
}
}
public static void after() {
Trace trace = TraceWrapper.getTrace(); //Trace类,可自行实现,不是关键
if (null != trace) {
if (trace.callMethodSize() > 0) {
CallMethod callMethod = trace.pop();
if (null != callMethod && callMethod.isTraceFlag()) {
callMethod.calculateCostTime();
trace.addTraceRecord(new TraceRecord(callMethod));
}
if (trace.callMethodSize() == 0) {
List traceRecordList = trace.getAllTraceRecord();
if (null != traceRecordList && traceRecordList.size() > 0) {
DBCollector collector = new DBCollector(traceRecordList);
new Thread(collector).start();
TraceWrapper.destory();
}
}
}
}
}
private static void before(Method method) {
Trace trace = TraceWrapper.getTrace();
CallMethod callMethod = new CallMethod(method);
if (isInnerClass(callMethod)) { //spring中有很多内部类,可以去掉
callMethod.setTraceFlag(false);
} else {
callMethod.setTraceFlag(true);
}
//不管是否跟踪都放进去
trace.push(callMethod);
}
private static boolean isInnerClass(CallMethod callMethod) {
return callMethod.getClassName().indexOf("$") > -1;
}
}
3.AbstractJunction.java
package com.javashizhan.trace.interceptor; import net.bytebuddy.matcher.ElementMatcher; import net.bytebuddy.matcher.ElementMatcher.Junction; import net.bytebuddy.matcher.ElementMatcher.Junction.Conjunction; import net.bytebuddy.matcher.ElementMatcher.Junction.Disjunction; public abstract class AbstractJunctionimplements ElementMatcher.Junction { @Override public Junction and(ElementMatcher super U> other) { return new Conjunction(this, other); } @Override public Junction or(ElementMatcher super U> other) { return new Disjunction(this, other); } }
4.ProtectiveShieldMatcher.java
package com.javashizhan.trace.interceptor; import net.bytebuddy.matcher.ElementMatcher; public class ProtectiveShieldMatcher三、pom文件extends ElementMatcher.Junction.AbstractBase { private final ElementMatcher super T> matcher; public ProtectiveShieldMatcher(ElementMatcher super T> matcher) { this.matcher = matcher; } public boolean matches(T target) { try { return this.matcher.matches(target); } catch (Throwable t) { //logger.warn(t, "Byte-buddy occurs exception when match type."); return false; } } }
四、在Java应用中添加启动参数4.0.0 trace chain 0.0.1-SNAPSHOT UTF-8 1.8 1.8 1.8 net.bytebuddy byte-buddy 1.9.6 net.bytebuddy byte-buddy-agent 1.9.6 com.zaxxer HikariCP 2.7.9 mysql mysql-connector-java 8.0.16 org.apache.maven.plugins maven-shade-plugin 3.0.0 package shade com.javashizhan.trace.TraceAgent maven-clean-plugin 3.1.0 maven-resources-plugin 3.0.2 maven-compiler-plugin 3.8.0 maven-surefire-plugin 2.22.1 maven-jar-plugin 3.0.2 maven-install-plugin 2.5.2 maven-deploy-plugin 2.8.2 maven-site-plugin 3.7.1 maven-project-info-reports-plugin 3.0.0
1.先将agent工程打成jar包
2.在要使用agent的Java应用中添加如下VM启动参数
-javaagent:D:MyAppapache-skywalking-apm-binagentchain-0.0.1-SNAPSHOT.jar
注意自行替换jar包路径。
end.
加入《Java栈实战营》知识星球,参与讨论,更多实战代码分享,不就是几斤苹果,几个荣耀道具的事吗!
https://t.zsxq.com/RNzfi2j
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/75792.html
摘要:微服务中调用栈的获取,使用的开发者会很自然想到用来拦截,但是拦截同一个类的多个方法之间的调用很不方便,有侵入性,因此并不适合。调用栈的跟踪也提供了这个能力,可以获得当前方法的调用栈信息。 一、调用链跟踪的作用 调用链跟踪包括 1.前端到后端的调用链 2.单个服务内部方法之间的调用链 3.微服务之间的调用链 4.应用服务和数据库之间的调用链 5.应用服务和第三方服务中...
摘要:除了以上级别的成员变量共享,在调用链跟踪时要能识别不同分层下的多个类实例的调用是同一个请求,而这个请求的调用都在一个独立线程内完成,此时就要用到线程级变量共享。 一、Java类成员作用域 JAVA类成员作用域参考下图: showImg(https://segmentfault.com/img/bVbvWlh?w=1695&h=925); Java虚拟机级作用域,通过在类成员变量前加...
摘要:一调用栈调用链监控仅仅获取调用顺序是不够的,如前所描述左边只体现了顺序,右边体现了顺序和调用栈信息。二获取调用栈在中获取调用栈的方法如下代码示例输出结果可以看到第个栈是调用的方法。 一、调用栈 调用链监控仅仅获取调用顺序是不够的,如前所描述: showImg(https://segmentfault.com/img/bVbvV9H?w=500&h=230);左边只体现了顺序,右边体现...
摘要:一监控一般思路中监控一般通过代理模式实现,如下右边是接口类。配置将项目下文件放到目录下或者中,找到将类名修改为你自己的实现类,并去掉其他所有配置都不用修改就可以监控到。至此,可以监控到语句了。 一、SQL监控一般思路 Java中SQL监控一般通过代理模式实现,如下: showImg(https://segmentfault.com/img/bVbvWML?w=2187&h=1090)...
阅读 1407·2021-09-22 15:32
阅读 1916·2019-08-30 15:53
阅读 3496·2019-08-30 15:53
阅读 1638·2019-08-30 15:43
阅读 667·2019-08-28 18:28
阅读 2797·2019-08-26 18:18
阅读 867·2019-08-26 13:58
阅读 2735·2019-08-26 12:10