文档章节

【JAVA基础☞探针技术】Java探针-Java Agent技术

卯金刀GG
 卯金刀GG
发布于 06/26 14:20
字数 1337
阅读 142
收藏 2

1、原理:基于javaAgent和Java字节码注入技术的java探针工具技术原理

2、原理分析

动态代理功能实现说明,我们利用javaAgent和ASM字节码技术开发java探针工具,实现原理如下:

jdk1.5以后引入了javaAgent技术,javaAgent是运行方法之前的拦截器。我们利用javaAgent和ASM字节码技术,在JVM加载class二进制文件的时候,利用ASM动态的修改加载的class文件,在监控的方法前后添加计时器功能,用于计算监控方法耗时,同时将方法耗时及内部调用情况放入处理器,处理器利用栈先进后出的特点对方法调用先后顺序做处理,当一个请求处理结束后,将耗时方法轨迹和入参map输出到文件中,然后根据map中相应参数或耗时方法轨迹中的关键代码区分出我们要抓取的耗时业务。最后将相应耗时轨迹文件取下来,转化为xml格式并进行解析,通过浏览器将代码分层结构展示出来,方便耗时分析,如图下图所示。

Java探针工具功能点:

1、支持方法执行耗时范围抓取设置,根据耗时范围抓取系统运行时出现在设置耗时范围的代码运行轨迹。

2、支持抓取特定的代码配置,方便对配置的特定方法进行抓取,过滤出关系的代码执行耗时情况。

3、支持APP层入口方法过滤,配置入口运行前的方法进行监控,相当于监控特有的方法耗时,进行方法专题分析。

4、支持入口方法参数输出功能,方便跟踪耗时高的时候对应的入参数。

5、提供WEB页面展示接口耗时展示、代码调用关系图展示、方法耗时百分比展示、可疑方法凸显功能。

3、实例:

JavaAgent 是JDK 1.5 以后引入的,也可以叫做Java代理。

JavaAgent 是运行在 main方法之前的拦截器,它内定的方法名叫 premain ,也就是说先执行 premain 方法然后再执行 main 方法。

查看原作者实例地址:https://www.cnblogs.com/aspirant/p/8796974.html

JavaAgent 的应用场景

JDK5中只能通过命令行参数在启动JVM时指定javaagent参数来设置代理类,而JDK6中已经不仅限于在启动JVM时通过配置参数来设置代理类,JDK6中通过 Java Tool API 中的 attach 方式,我们也可以很方便地在运行过程中动态地设置加载代理类,以达到 instrumentation 的目的。 
Instrumentation 的最大作用,就是类定义动态改变和操作。

最简单的一个例子,计算某个方法执行需要的时间,不修改源代码的方式,使用Instrumentation 代理来实现这个功能,给力的说,这种方式相当于在JVM级别做了AOP支持,这样我们可以在不修改应用程序的基础上就做到了AOP。

  1. 创建一个 ClassFileTransformer 接口的实现类 MyTransformer 
    实现 ClassFileTransformer 这个接口的目的就是在class被装载到JVM之前将class字节码转换掉,从而达到动态注入代码的目的。那么首先要了解MonitorTransformer 这个类的目的,就是对想要修改的类做一次转换,这个用到了javassist对字节码进行修改,可以暂时不用关心jaavssist的原理,用ASM同样可以修改字节码,只不过比较麻烦些。
  2. 代码:
    package com.shanhy.demo.agent;
    
    import java.lang.instrument.ClassFileTransformer;
    import java.lang.instrument.IllegalClassFormatException;
    import java.security.ProtectionDomain;
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    import javassist.ClassPool;
    import javassist.CtClass;
    import javassist.CtMethod;
    import javassist.CtNewMethod;
    
    /**
     * 检测方法的执行时间
     *
     */
    public class MyTransformer implements ClassFileTransformer {
    
        final static String prefix = "\nlong startTime = System.currentTimeMillis();\n";
        final static String postfix = "\nlong endTime = System.currentTimeMillis();\n";
    
        // 被处理的方法列表
        final static Map<String, List<String>> methodMap = new HashMap<String, List<String>>();
    
        public MyTransformer() {
            add("com.shanhy.demo.TimeTest.sayHello");
            add("com.shanhy.demo.TimeTest.sayHello2");
        }
    
        private void add(String methodString) {
            String className = methodString.substring(0, methodString.lastIndexOf("."));
            String methodName = methodString.substring(methodString.lastIndexOf(".") + 1);
            List<String> list = methodMap.get(className);
            if (list == null) {
                list = new ArrayList<String>();
                methodMap.put(className, list);
            }
            list.add(methodName);
        }
    
        @Override
        public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined,
                ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
            className = className.replace("/", ".");
            if (methodMap.containsKey(className)) {// 判断加载的class的包路径是不是需要监控的类
                CtClass ctclass = null;
                try {
                    ctclass = ClassPool.getDefault().get(className);// 使用全称,用于取得字节码类<使用javassist>
                    for (String methodName : methodMap.get(className)) {
                        String outputStr = "\nSystem.out.println(\"this method " + methodName
                                + " cost:\" +(endTime - startTime) +\"ms.\");";
    
                        CtMethod ctmethod = ctclass.getDeclaredMethod(methodName);// 得到这方法实例
                        String newMethodName = methodName + "$old";// 新定义一个方法叫做比如sayHello$old
                        ctmethod.setName(newMethodName);// 将原来的方法名字修改
    
                        // 创建新的方法,复制原来的方法,名字为原来的名字
                        CtMethod newMethod = CtNewMethod.copy(ctmethod, methodName, ctclass, null);
    
                        // 构建新的方法体
                        StringBuilder bodyStr = new StringBuilder();
                        bodyStr.append("{");
                        bodyStr.append(prefix);
                        bodyStr.append(newMethodName + "($$);\n");// 调用原有代码,类似于method();($$)表示所有的参数
                        bodyStr.append(postfix);
                        bodyStr.append(outputStr);
                        bodyStr.append("}");
    
                        newMethod.setBody(bodyStr.toString());// 替换新方法
                        ctclass.addMethod(newMethod);// 增加新方法
                    }
                    return ctclass.toBytecode();
                } catch (Exception e) {
                    System.out.println(e.getMessage());
                    e.printStackTrace();
                }
            }
            return null;
        }
    }

     

 

本文转载自:https://www.cnblogs.com/aspirant/p/8796974.html

卯金刀GG
粉丝 26
博文 266
码字总数 73176
作品 0
昌平
程序员
私信 提问
如何批量更新ARMS应用监控的应用探针

ARMS 应用监控应用探针 安装原理 和 更新问题 ARMS的Java的程序的应用监控原理和其他大多数APM产品类似,通过在Java程序中挂载应用探针(javaagent)来完成,如下图所示。整个安装步骤一般分为...

中间件小哥
2018/07/02
0
0
如何提高阿里云上应用的可用性(一)

如今,开发并上线一款应用十分方便。因为云计算提供了从最基础的计算资源如服务器网络、数据库服务、中间件PaaS平台到各种应用支撑的云管理服务,同时开源社区的迅猛发展也提供了从数据库、缓...

阿里云云栖社区
2018/11/08
31
0
阿里巴巴产品专家:如何提高阿里云云上应用的可用性

如今,开发并上线一款应用十分方便。因为云计算提供了从最基础的计算资源如服务器网络、数据库服务、中间件PaaS平台到各种应用支撑的云管理服务,同时开源社区的迅猛发展也提供了从数据库、缓...

中间件小哥
2018/10/31
0
0
Java udp程序 如何接收c 语言udp发送的结构体数据

有一个wifi探针设备,会不断向java提供的udp服务器发送udp 结构体数据,java udp服务程序需要接收 探针设备发送的 用 c写的结构体数据,如下是C 的接收数据,如何转为java接收 结构体数据, ...

KerryLi
2017/08/18
303
1
sky-walking 3.2 发布,Java Server APM

经过三个半月的大规模重构,sky-walking 3.2版本发布。 此版本是第一个3.2版本,相对于3.1.x版本,sky-walking移除了对于akka的依赖,并在Collector端引入模块化架构,并在3.2的第一个版本中...

wu-sheng
2017/09/19
1K
6

没有更多内容

加载失败,请刷新页面

加载更多

Spring Boot 2 实战:使用 Spring Boot Admin 监控你的应用

1. 前言 生产上对 Web 应用 的监控是十分必要的。我们可以近乎实时来对应用的健康、性能等其他指标进行监控来及时应对一些突发情况。避免一些故障的发生。对于 Spring Boot 应用来说我们可以...

码农小胖哥
16分钟前
2
0
ZetCode 教程翻译计划正式启动 | ApacheCN

原文:ZetCode 协议:CC BY-NC-SA 4.0 欢迎任何人参与和完善:一个人可以走的很快,但是一群人却可以走的更远。 ApacheCN 学习资源 贡献指南 本项目需要校对,欢迎大家提交 Pull Request。 ...

ApacheCN_飞龙
27分钟前
2
0
CSS定位

CSS定位 relative相对定位 absolute绝对定位 fixed和sticky及zIndex relative相对定位 position特性:css position属性用于指定一个元素在文档中的定位方式。top、right、bottom、left属性则...

studywin
35分钟前
5
0
从零基础到拿到网易Java实习offer,我做对了哪些事

作为一个非科班小白,我在读研期间基本是自学Java,从一开始几乎零基础,只有一点点数据结构和Java方面的基础,到最终获得网易游戏的Java实习offer,我大概用了半年左右的时间。本文将会讲到...

Java技术江湖
昨天
5
0
程序性能checklist

程序性能checklist

Moks角木
昨天
7
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部