本文建立在对instrumentation和agent有初步的了解的前提下阅读,关于这2个类的讲解在其它文章中。

这是一个maven项目,pom中需要的配置,lib中有asm的jar包

pom.xml文件:

<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <groupId>com.dxz</groupId>
<artifactId>chama</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging> <name>chama</name>
<url>http://maven.apache.org</url> <properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties> <dependencies>
<dependency>
<groupId>org.ow2.asm</groupId>
<artifactId>asm-test</artifactId>
<version>6.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.ow2.asm</groupId>
<artifactId>asm-analysis</artifactId>
<version>6.2</version>
</dependency>
<dependency>
<groupId>org.ow2.asm</groupId>
<artifactId>asm-commons</artifactId>
<version>6.2</version>
</dependency>
<dependency>
<groupId>org.ow2.asm</groupId>
<artifactId>asm-tree</artifactId>
<version>6.2</version>
</dependency>
<dependency>
<groupId>org.ow2.asm</groupId>
<artifactId>asm-util</artifactId>
<version>6.2</version>
</dependency>
<dependency>
<groupId>javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.12.1.GA</version>
</dependency> <!-- https://mvnrepository.com/artifact/cglib/cglib -->
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.2.5</version>
</dependency> <!-- https://mvnrepository.com/artifact/oro/oro -->
<dependency>
<groupId>oro</groupId>
<artifactId>oro</artifactId>
<version>2.0.8</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>utf-8</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.0.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer
implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<manifestEntries>
<!-- <Premain-Class>com.dxz.chama.javaagent.patter.TimeMonitorPatterAgent</Premain-Class> -->
<!-- <Premain-Class>com.dxz.chama.javaagent.StatAgent</Premain-Class> -->
<Premain-Class>com.dxz.chama.javaagent.asm.UdAgent</Premain-Class>
</manifestEntries>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

打包后的agent的jar包中manifest属性如下:

agent类,只有一个方法,就是把自定义的类修改器添加到instrumentation中。

package com.dxz.chama.javaagent.asm;

import java.lang.instrument.Instrumentation;

public class UdAgent {
public static void premain(String agentArgs, Instrumentation instrumentation){
instrumentation.addTransformer(new LogTransformer());
}
}

类转换器实现:

package com.dxz.chama.javaagent.asm;

import java.io.IOException;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.security.ProtectionDomain; import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassWriter; public class LogTransformer implements ClassFileTransformer {
@Override
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined,
ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
try {
ClassReader cr = new ClassReader(className);
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
TimeCountAdpter timeCountAdpter = new TimeCountAdpter(cw); cr.accept(timeCountAdpter, ClassReader.EXPAND_FRAMES); return cw.toByteArray();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}

实际修改字节码的方法,这里给每个类添加了一个字段UDASMCN,用于记录当前类的名字(方便打印信息)。同时记录每个方法的名字,以及执行时间。

package com.dxz.chama.javaagent.asm;

import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.commons.AnalyzerAdapter;
import org.objectweb.asm.commons.LocalVariablesSorter; public class TimeCountAdpter extends ClassVisitor implements Opcodes {
private String owner;
private boolean isInterface;
private String filedName = "UDASMCN";
private int acc = Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC + Opcodes.ACC_FINAL;
private boolean isPresent = false; private String methodName; public TimeCountAdpter(ClassVisitor classVisitor) {
super(ASM6, classVisitor);
} @Override
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
super.visit(version, access, name, signature, superName, interfaces);
owner = name;
isInterface = (access & ACC_INTERFACE) != 0;
} @Override
public FieldVisitor visitField(int access, String name, String descriptor, String signature, Object value) {
if (name.equals(filedName)) {
isPresent = true;
}
return super.visitField(access, name, descriptor, signature, value);
} @Override
public MethodVisitor visitMethod(int access, String name, String descriptor, String signature,
String[] exceptions) {
MethodVisitor mv = cv.visitMethod(access, name, descriptor, signature, exceptions); if (!isInterface && mv != null && !name.equals("<init>") && !name.equals("<clinit>")) {
methodName = name;
AddTimerMethodAdapter at = new AddTimerMethodAdapter(mv);
at.aa = new AnalyzerAdapter(owner, access, name, descriptor, at);
at.lvs = new LocalVariablesSorter(access, descriptor, at.aa); return at.lvs;
} return mv;
} public void visitEnd() {
if (!isInterface) {
FieldVisitor fv = cv.visitField(acc, filedName, "Ljava/lang/String;", null, owner);
if (fv != null) {
fv.visitEnd();
}
}
cv.visitEnd();
} class AddTimerMethodAdapter extends MethodVisitor {
private int time;
private int maxStack;
public LocalVariablesSorter lvs;
public AnalyzerAdapter aa; public AddTimerMethodAdapter(MethodVisitor methodVisitor) {
super(ASM6, methodVisitor);
} @Override
public void visitCode() {
mv.visitCode();
mv.visitMethodInsn(INVOKESTATIC, "java/lang/System", "nanoTime", "()J", false);
time = lvs.newLocal(Type.LONG_TYPE);
mv.visitVarInsn(LSTORE, time);
maxStack = 4;
} @Override
public void visitInsn(int opcode) {
if (((opcode >= IRETURN && opcode <= RETURN) || opcode == ATHROW) && !isPresent) {
mv.visitMethodInsn(INVOKESTATIC, "java/lang/System", "nanoTime", "()J", false);
mv.visitVarInsn(LLOAD, time);
mv.visitInsn(LSUB);
mv.visitVarInsn(LSTORE, time); mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"); mv.visitTypeInsn(NEW, "java/lang/StringBuilder");
mv.visitInsn(DUP);
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/StringBuilder", "<init>", "()V", false);
mv.visitFieldInsn(GETSTATIC, owner, filedName, "Ljava/lang/String;");
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append",
"(Ljava/lang/String;)Ljava/lang/StringBuilder;", false); mv.visitLdcInsn(" " + methodName + ":");
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append",
"(Ljava/lang/String;)Ljava/lang/StringBuilder;", false); mv.visitVarInsn(LLOAD, time);
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(J)Ljava/lang/StringBuilder;",
false);
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "toString", "()Ljava/lang/String;", false);
mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false); maxStack = Math.max(aa.stack.size() + 4, maxStack);
}
mv.visitInsn(opcode);
} @Override
public void visitMaxs(int maxStack, int maxLocals) {
super.visitMaxs(Math.max(maxStack, this.maxStack), maxLocals);
}
} }

打包成jar包后,在另一个程序启动时调用,启动参数如下:

-javaagent:D:\study\chama\target\chama-0.0.1-SNAPSHOT.jar
执行效果:
时间单位是纳秒,可以看到每个方法执行完时,都会打印这个方法 的执行时间,以com/Main main:11457636为例,说明类com/Main的main方法执行力11毫秒。

JVM插码之五:Java agent+ASM实战--监控所有方法执行时间的更多相关文章

  1. Java 调式、热部署、JVM 背后的支持者 Java Agent

    我们平时写 Java Agent 的机会确实不多,也可以说几乎用不着.但其实我们一直在用它,而且接触的机会非常多.下面这些技术都使用了 Java Agent 技术,看一下你就知道为什么了. -各个 J ...

  2. JVM插码之四:Java动态代理机制的对比(JDK 和CGLIB,Javassist,ASM)

    一.class文件简介及加载 Java编译器编译好Java文件之后,产生.class 文件在磁盘中.这种class文件是二进制文件,内容是只有JVM虚拟机能够识别的机器码.JVM虚拟机读取字节码文件, ...

  3. JVM插码之三:javaagent介绍及javassist介绍

    本文介绍一下,当下比较基础但是使用场景却很多的一种技术,稍微偏底层点,就是字节码插庄技术了...,如果之前大家熟悉了asm,cglib以及javassit等技术,那么下面说的就很简单了...,因为下面 ...

  4. JVM插码之六:jacoco插码及问题“$jacocodata 属性 Method not found: is$jacocoData”

    在使用jacoco统计自动化代码覆盖率 jacoco统计自动化代码覆盖率 1. 简介1.1. 什么是JacocoJacoco是一个开源的代码覆盖率工具,可以嵌入到Ant .Maven中,并提供了Ecl ...

  5. 基于Java Agent的premain方式实现方法耗时监控(转),为了找到结论执行:premain在jvm启动的时候执行,所有方法前,会执行MyAgent的premain方法

    Java Agent是依附于java应用程序并能对其字节码做相关更改的一项技术,它也是一个Jar包,但并不能独立运行,有点像寄生虫的感觉.当今的许多开源工具尤其是监控和诊断工具,很多都是基于Java ...

  6. jvm源码解析java对象头

    认真学习过java的同学应该都知道,java对象由三个部分组成:对象头,实例数据,对齐填充,这三大部分扛起了java的大旗对象,实例数据其实就是我们对象中的数据,对齐填充是由于为了规则分配内存空间,j ...

  7. jvm源码解读--20 结合jvm源码理解 java 设计模式 模板方法

    write by 张艳涛 前言: 在学习jvm之前,看过设计模式的书,知道模板方法的设计模式,今天在看java并发编程的艺术里面关于AbstractQueuedSynchronizer 用法,这个就使 ...

  8. 🏆【Java技术专区】「探针Agent专题」Java Agent探针的技术介绍(1)

    前提概要 Java调式.热部署.JVM背后的支持者Java Agent: 各个 Java IDE 的调试功能,例如 eclipse.IntelliJ : 热部署功能,例如 JRebel.XRebel. ...

  9. 探秘 Java 热部署二(Java agent premain)

    # 前言 在前文 探秘 Java 热部署 中,我们通过在死循环中重复加载 ClassLoader 和 Class 文件实现了热部署的功能,但我们也指出了缺点-----不够灵活.需要手动修改文件等操作. ...

随机推荐

  1. SpingBoot一——demo及阿里云部署

    ◆版权声明:本文出自胖喵~的博客,转载必须注明出处. 转载请注明出处:https://www.cnblogs.com/by-dream/p/9957624.html 双11买了阿里云的服务器,后续计划 ...

  2. DevExpress v18.1新版亮点——ASP.NET篇(四)

    用户界面套包DevExpress v18.1日前终于正式发布,本站将以连载的形式为大家介绍各版本新增内容.本文将介绍了DevExpress ASP.NET v18.1 的新功能,快来下载试用新版本!点 ...

  3. 由pg_xlogdump统计信息想到的问题

    最近深入理解了Checkpoint的相关逻辑,再来看WAL日志的一些设置,又有了新的收获. 1.回顾pg_xlogdump出来的wal日志信息: 2.wal中FPI的占比很高问题分析: 3.重申ful ...

  4. xcode cocos2dx升级

    原文转自:http://www.codeo4.cn/archives/690 cocos2d-x的安装脚本里没有升级的脚本,我们如果在新版本安装的时候加上参数:-f 强制安装也没有能完全解决问题.新建 ...

  5. JSP--TOMCAT-MYSQL web页面添加

    addStudent.jsp如下<%@ page language="java" import="java.util.*" pageEncoding=&q ...

  6. diary of django

    1.安装django -> pip install django ----- 某些时候竟然需要FQ 2.JsonResponse 需要    (不需要了,django.http自带) pip i ...

  7. 新手小白Linux(Centos6.5)部署java web项目(mysql5.7安装及相关操作)

    一.安装 参考:https://dev.mysql.com/doc/refman/5.7/en/linux-installation-yum-repo.html # 检测系统中是否安装了mysql y ...

  8. The Alphabet Sticker

    题目大意:给你一串字符串,其中有一部分未知,用'?'表示. 现在定义一种合法的Sticker,比如"aabcc","ccccab".即所有相同的字母要在一起才是 ...

  9. C易忽视的基础

    1.输出格式控制:%x按int型16进制输出: %d按int型十进制输出:变量超出4字节会丢掉低位!!!!(却不是被截断!!!) void main() { int a=0x11223344; lon ...

  10. c#代码获取web.config配置文件里面设置的 <compilation debug="true"节点

    == 在我们的web.config文件中,有像下面的这样的一个配置, <system.web> <identity impersonate="true" user ...