java instrumentation &JVMTI
Java Instrumentation (参考:http://www.ibm.com/developerworks/cn/java/j-lo-jse61/)
简介:
使用Instrumentation,开发者可以构建独立于应用程序的代理程序,用来检测和协助运行在JVM上的程序,甚至能够替换和修改某些类的定义
遇到问题:
运行在tomcat容器中的应用程序,由于main方法是在Bootstrap.jar中容器启动时执行的,
Agent-class方式在替换的方法中只获取到tomcat相关jar包中的一些类:

上图中是在transform方法中打印出来的,这个方法会在二中介绍
具体介绍:
下面是两种方式PreMain 和 agentMain,分别为main函数执行之前,和执行之后的操作
一:PreMain
main函数执行之间,扫描判断特定的类,然后以字节数组的方式加载代理类的字节码文件,替换目标类:
示例代码:
public class TransClass {
public int getNumber() {
return 2;
}
}
TransClass
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.security.ProtectionDomain; class Transformer implements ClassFileTransformer {
public static final String classNumberReturns2 = "D://AOP//TransClass.class.2";
public static byte[] getBytesFromFile(String fileName) {
try {
// precondition
File file = new File(fileName);
InputStream is = new FileInputStream(file);
long length = file.length();
byte[] bytes = new byte[(int) length]; // Read in the bytes
int offset = 0;
int numRead = 0;
while (offset <bytes.length && (numRead = is.read(bytes, offset, bytes.length - offset)) >= 0) {
offset += numRead;
}
if (offset < bytes.length) {
throw new IOException("Could not completely read file "+ file.getName());
}
is.close();
return bytes;
} catch (Exception e) {
System.out.println("error occurs in _ClassTransformer!"+ e.getClass().getName());
return null;
}
} public byte[] transform(ClassLoader l, String className, Class<?> c,
ProtectionDomain pd, byte[] b) throws IllegalClassFormatException {
if (!className.equals("TransClass")) {
return null;
}
return getBytesFromFile(classNumberReturns2);
}
}
Transformer
public class TestMainInJar {
public static void main(String[] args) {
System.out.println(new TransClass().getNumber());
}
}
TestMainInJar
import java.lang.instrument.UnmodifiableClassException;
import java.lang.instrument.Instrumentation;
public class Premain {
public static void premain(String agentArgs, Instrumentation inst)
throws ClassNotFoundException, UnmodifiableClassException {
inst.addTransformer(new Transformer());
}
}
Premain
Manifest-Version: 1.0
Premain-Class: Premain
MANIFEST.MF
步骤:
1. TransClass.java 中 改成 return 2; 之后编译生成的TransClass.class改名为TransClass.class.2 ,以防止跟原TransClass.class重名
2. 打包:jar -cvf0 TestInstrument1.jar TransClass.class Transformer.class TestMainInJar.class Premain.class
打好jar后替换manifest.mf文件,(没找到怎么把这个文件直接打进jar包)
3. 命令行执行
1)java -javaagent:TestInstrument1.jar -cp TestInstrument1.jar TestMainInJar
2)java -cp TestInstrument1.jar TestMainInJar
(TransClass.class.2 和 TestInstrument1.jar 需要放置到 D:\AOP 目录下)
用第一个命令执行的时候,会把TransClass.class.2的内容加载进来替换jar包中的TransClass.class,而第二个命令是正常执行jar包中的TransClass.class
二: Agent-class
import java.lang.instrument.Instrumentation;
public class LoadedAgent {
@SuppressWarnings("rawtypes")
public static void agentmain(String args, Instrumentation inst){
Class[] classes = inst.getAllLoadedClasses();
//inst.addTransformer(new Transformer());
for(Class cls :classes){
System.out.println(cls.getName());
}
}
}
LoadedAgent
public class TargetVM {
public static void main(String[] args) throws InterruptedException{
while(true){
Thread.sleep(1000);
}
}
}
TargetVM
import java.io.IOException; import com.sun.tools.attach.AgentInitializationException;
import com.sun.tools.attach.AgentLoadException;
import com.sun.tools.attach.AttachNotSupportedException;
import com.sun.tools.attach.VirtualMachine; public class Test {
public static void main(String[] args) throws AttachNotSupportedException,
IOException, AgentLoadException, AgentInitializationException {
VirtualMachine vm = VirtualMachine.attach("1244");
vm.loadAgent("D:/AOP/agentmain/agentAop.jar"); } }
Test
Manifest-Version: 1.0
Agent-Class: LoadedAgent
MANIFEST.MF
步骤:
1. 将LoadedAgent.class 和 Manifest.mf打进jar包
2. 执行TargetVM.class 获取进程号PID
3. 执行Test.class pid作为参数
注意:
1. 编译时需要用到jdk中lib目录下的tools.jar javac -cp tools.jar Test.java
2. 执行命令(1244 是进程号) :java -classpath "D:/AOP/agentmain/tools.jar" Test 1244
java instrumentation &JVMTI的更多相关文章
- Java Instrumentation插桩技术学习
Instrumentation基础 openrasp中用到了Instrumentation技术,它的最大作用,就是类的动态改变和操作. 使用Instrumentation实际上也可以可以开发一个代理来 ...
- Java - Instrumentation
使用JRebel启动工程时加上VM参数时有一个参数是"-javaagent:D:\jrebel_5.6.0\jrebel.jar". javaagent是什么? java -hel ...
- 曹工说Spring Boot源码(25)-- Spring注解扫描的瑞士军刀,ASM + Java Instrumentation,顺便提提Jar包破解
写在前面的话 相关背景及资源: 曹工说Spring Boot源码(1)-- Bean Definition到底是什么,附spring思维导图分享 曹工说Spring Boot源码(2)-- Bean ...
- java高级-动态注入替换类Instrumentation
介绍 利用java.lang.instrument(容器类) 做动态 Instrumentation(执行容器) 是 Java SE 5 的新特性. 使用 Instrumentation,开发者可以构 ...
- 极客时间-左耳听风-程序员攻略-Java底层知识
Java 字节码相关 字节码编程,也就是动态修改或是动态生成 Java 字节码.Java 的字节码相当于汇编,其中的一些细节. Java Zone: Introduction to Java Byte ...
- java agent技术原理及简单实现
注:本文定义-在函数执行前后增加对应的逻辑的操作统称为MOCK 1.引子 在某天与QA同学进行沟通时,发现QA同学有针对某个方法调用时,有让该方法停止一段时间的需求,我对这部分的功能实现非常好奇,因此 ...
- Java 动态调试技术原理及实践
本文转载自Java 动态调试技术原理及实践 导语 断点调试是我们最常使用的调试手段,它可以获取到方法执行过程中的变量信息,并可以观察到方法的执行路径.但断点调试会在断点位置停顿,使得整个应用停止响应. ...
- Java 中的纤程库 – Quasar
来源:鸟窝, colobu.com/2016/07/14/Java-Fiber-Quasar/ 如有好文章投稿,请点击 → 这里了解详情 最近遇到的一个问题大概是微服务架构中经常会遇到的一个问题: 服 ...
- java基础-01基本概念
java的特点 跨平台 所谓的平台,我们可以理解为操作系统. 大部分语言是不能跨平台的,比如c语言的程序在windows和linux上需要编写不同的代码. java程序是运行在JVM(Java Vir ...
随机推荐
- Mustache(2)
Web 模板引擎是为了使用户界面与业务数据(内容)分离而产生的,它可以生成特定格式的文档,通常是标准的 HTML 文档.当然不同的开发语言有不同模板引擎,如 Javascript 下的 Hogan . ...
- matlab小数分数转换
>> format short %%%% MATLAB默认格式,小数显示 >> format rat %%%%% 转成分数表示
- Golang数组的四种声明方法
//第一种 //var <数组名称> [<数组长度>]<数组元素> var arr [2]int arr[0]=1 arr[1]=2 //第二种 //var < ...
- go语言发送邮件
package main import ( "fmt" "net/smtp" "strings" ) //发送邮件的逻辑函数 func Se ...
- [Spring Data MongoDB]学习笔记--_id和类型映射
_id字段的映射: MongoDB要求所有的document都要有一个_id的字段. 如果我们在使用中没有传入_id字段,它会自己创建一个ObjectId. { , "accounts&qu ...
- 160819、JavaScript-数组去重由慢到快由繁到简
JavaScript-数组去重由慢到快由繁到简演化 indexOf去重 Array.prototype.unique1 = function() { var arr = []; for (var ...
- IDEA : Git Pull Failed 解决(IDEA中使用stash功能)
一.问题: 本地要commit代码,commit之前需pull代码,但pull提示冲突.如下 Git Pull Failed Your local changes would be overwritt ...
- coursera 《现代操作系统》 -- 第五周 同步机制(1)
临界区块(Critical section)指的是一个访问共用资源(例如:共用设备或是共用存储器)的程序片段,而这些共用资源有无法同时被多个线程访问的特性.(不是字面意思的一个区域,是程序片段的集合) ...
- 任务05—学习 MARKDOWN 语言
我的简历地址: https://github.com/jinxiaohang/MyResume/blob/master/ForJavaJob.md 本任务主要目的掌握markdown. 1.首先是工具 ...
- ehcache 的HelloWorld实现(二)
EhCache最新版本是3.X 本人一直用的是2.X 比较稳定 功能足够用: 所以还是用2.X版本: 我们新建一个Maven项目, pom.xml里引入 ehcache支持: <dependen ...