资讯专栏INFORMATION COLUMN

Java调用链跟踪关键技术(二)Javaagent

geekzhou / 3310人阅读

摘要:一网上关于的介绍很多,请找度娘和谷兄。唯一提的一点是字节码注入比较好用的是,封装度很高,使用简单。二代码样例以下为关键代码样例,可以依样画瓢自行改造。加入栈实战营知识星球,参与讨论,更多实战代码分享,不就是几斤苹果,几个荣耀道具的事吗

一、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 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 AbstractJunction implements ElementMatcher.Junction {
    @Override
    public  Junction and(ElementMatcher other) {
        return new Conjunction(this, other);
    }

    @Override
    public  Junction or(ElementMatcher other) {
        return new Disjunction(this, other);
    }
}

4.ProtectiveShieldMatcher.java

package com.javashizhan.trace.interceptor;

import net.bytebuddy.matcher.ElementMatcher;

public class ProtectiveShieldMatcher extends ElementMatcher.Junction.AbstractBase {

    private final ElementMatcher matcher;

    public ProtectiveShieldMatcher(ElementMatcher 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;
        }
    }
}
三、pom文件

  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
                
            
        
    
四、在Java应用中添加启动参数

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

相关文章

  • Java调用跟踪关键技术(一)总体介绍

    摘要:微服务中调用栈的获取,使用的开发者会很自然想到用来拦截,但是拦截同一个类的多个方法之间的调用很不方便,有侵入性,因此并不适合。调用栈的跟踪也提供了这个能力,可以获得当前方法的调用栈信息。 一、调用链跟踪的作用 调用链跟踪包括 1.前端到后端的调用链 2.单个服务内部方法之间的调用链 3.微服务之间的调用链 4.应用服务和数据库之间的调用链 5.应用服务和第三方服务中...

    gaara 评论0 收藏0
  • Java调用跟踪关键技术(三)线程变量

    摘要:除了以上级别的成员变量共享,在调用链跟踪时要能识别不同分层下的多个类实例的调用是同一个请求,而这个请求的调用都在一个独立线程内完成,此时就要用到线程级变量共享。 一、Java类成员作用域 JAVA类成员作用域参考下图: showImg(https://segmentfault.com/img/bVbvWlh?w=1695&h=925); Java虚拟机级作用域,通过在类成员变量前加...

    ThreeWords 评论0 收藏0
  • Java调用跟踪关键技术(五)获取调用

    摘要:一调用栈调用链监控仅仅获取调用顺序是不够的,如前所描述左边只体现了顺序,右边体现了顺序和调用栈信息。二获取调用栈在中获取调用栈的方法如下代码示例输出结果可以看到第个栈是调用的方法。 一、调用栈 调用链监控仅仅获取调用顺序是不够的,如前所描述: showImg(https://segmentfault.com/img/bVbvV9H?w=500&h=230);左边只体现了顺序,右边体现...

    VPointer 评论0 收藏0
  • Java调用跟踪关键技术(四)SQL监控

    摘要:一监控一般思路中监控一般通过代理模式实现,如下右边是接口类。配置将项目下文件放到目录下或者中,找到将类名修改为你自己的实现类,并去掉其他所有配置都不用修改就可以监控到。至此,可以监控到语句了。 一、SQL监控一般思路 Java中SQL监控一般通过代理模式实现,如下: showImg(https://segmentfault.com/img/bVbvWML?w=2187&h=1090)...

    ?xiaoxiao, 评论0 收藏0

发表评论

0条评论

geekzhou

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<