摘要:一網上關于的介紹很多,請找度娘和谷兄。唯一提的一點是字節碼注入比較好用的是,封裝度很高,使用簡單。二代碼樣例以下為關鍵代碼樣例,可以依樣畫瓢自行改造。加入棧實戰營知識星球,參與討論,更多實戰代碼分享,不就是幾斤蘋果,幾個榮耀道具的事嗎
一、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) { ListtraceRecordList = 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
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/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)...
閱讀 1122·2021-09-22 15:32
閱讀 1722·2019-08-30 15:53
閱讀 3253·2019-08-30 15:53
閱讀 1404·2019-08-30 15:43
閱讀 453·2019-08-28 18:28
閱讀 2567·2019-08-26 18:18
閱讀 669·2019-08-26 13:58
閱讀 2528·2019-08-26 12:10