java agent
cmd使用java -help可以看到关于agent参数:
-agentlib:<libname>[=<选项>]
加载本机代理库 <libname>, 例如 -agentlib:hprof
另请参阅 -agentlib:jdwp=help 和 -agentlib:hprof=help
-agentpath:<pathname>[=<选项>]
按完整路径名加载本机代理库
-javaagent:<jarpath>[=<选项>]
加载 Java 编程语言代理, 请参阅 java.lang.instrument
其实这三个参数做的事情是一样的,都是java代理。
-agentlib和-agentpath使用的是本地代理也就是c/c++写的本地库(例如动态链接库dll和静态链接库lib),
而-javaagent使用java语言编写的jar。
关于这两种用法,我举两个具体的例子供大家参考,具体如下:
1.使用-agentlib和-agentpath加载本地库
我们使用C++来编写本地库,需要用到jdk中相关的头文件,这里需要用到的6个头文件在如下如下目录中:
%JAVA_HOME%\include目录下的:jawt.h, jni.h, jvmti.h, jvmticmlr.h
%JAVA_HOME%\include\win32目录下的:jawt_md.h, jni_md.h
我们使用visual studio 2017来编写我们的项目:
首先新建一个dll项目,如下

点击确定生成项目,然后把我们之前的6个头文件添加进项目中,后项目结构如下:

然后查看jvmti.h文件中的三个函数,并将其copy到我们的agent.cpp中去实现(需要在cpp文件中引入我们的头文件)

这里需要说明一点:
java agent有2个启动函数分别为Agent_OnLoad和Agent_OnAttach
* Agent_OnLoad在onload阶段被调用
* Agent_OnAttach在live阶段被调用
* 但是每个agent只有一个启动函数会被调用。
具体实现代码如下:
// Dll.cpp : 定义 DLL 应用程序的导出函数。
//
/*
* The VM starts each agent by invoking a start-up function.
* If the agent is started in the OnLoad phase the function Agent_OnLoad will be invoked.
* If the agent is started in the live phase the function Agent_OnAttach will be invoked.
* Exactly one call to a start-up function is made per agent.
* 中文总结一下上面的含义:
* java agent有2个启动函数分别为Agent_OnLoad和Agent_OnAttach
* Agent_OnLoad在onload阶段被调用
* Agent_OnAttach在live阶段被调用
* 但是每个agent只有一个启动函数会被调用
*/
#include "stdafx.h"
#include "jvmti.h"
#include <iostream> /*
* 此阶段JVM还没有初始化,所以能做的操作比较受限制
* JVM参数都无法获取
* The return value from Agent_OnLoad is used to indicate an error.
* Any value other than zero indicates an error and causes termination of the VM.
* 任何非零的返回值都会导致JVM终止。
*/ JNIEXPORT jint JNICALL
Agent_OnLoad(JavaVM *vm, char *options, void *reserved) {
jvmtiEnv* jvmti;
jvmtiCapabilities capabilities;
options = options == nullptr ? "" : options;
jint error = vm->GetEnv((void**)&jvmti, JVMTI_VERSION);
if (error) {
std::cout << "get jvmtiEnv error!\n";
}
else {
jvmti->GetCapabilities(&capabilities);
std::cout << "capabilities.can_access_local_variables : "
<< capabilities.can_access_local_variables
<< std::endl;
} std::cout << "Agent_OnLoad\n" << "options ===== " << options << std::endl; return ;
}
/*
* Any value other than zero indicates an error.
* An error does not cause the VM to terminate.
* Instead the VM ignores the error, or takes some implementation specific action -- for example it might print an error to standard error, or record the error in a system log.
*
*/
JNIEXPORT jint JNICALL
Agent_OnAttach(JavaVM* vm, char* options, void* reserved) {
options = options == nullptr ? "" : options;
std::cout << "Agent_OnAttach\n" << "options ===== " << options << std::endl; jvmtiEnv *jvmti;
jint result = vm->GetEnv((void**)&jvmti, JVMTI_VERSION);//获取jvmti指针
jint count;//用于保存加载类的数量
jclass* klasses;//指向保存已加载的类的指针
jvmtiError error = jvmti->GetLoadedClasses(&count, &klasses);//获取已加载的类和数量
std::cout << "jvmtiError : " << error << std::endl;
if (error)
std::cout << "get loadedClasses error!\n";
else {
std::cout << "signatures : \n";
for (int i = ; i < count; i++) {//循环打印类的签名
char* signature;
jvmti->GetClassSignature(klasses[i], &signature, NULL);
std::cout << signature << std::endl;
}
std::cout << "signatures end! ------------------\n";//已加载类签名打印结束标志
} jint threadCount;//用于保存线程数量
jthread* threads;//指向保存线程信息的指针
error = jvmti->GetAllThreads(&threadCount, &threads);//获取到线程信息
if (error)
std::cout << "get all threads error!\n";
else {
jvmtiThreadInfo threadInfo;//保存每个线程的信息,它是一个结构体的指针
for (size_t i = ; i < threadCount; i++) {
error = jvmti->GetThreadInfo(threads[i], &threadInfo);
if (error)
std::cout << "第 " << i << " 线程获取出错!\n";
else
std::cout << "thread name:" << threadInfo.name << std::endl;
}
std::cout << "thread info end! ---------------------\n";
} return ;
}
/*
* This function can be used to clean-up resources allocated by the agent.
*/
JNIEXPORT void JNICALL
Agent_OnUnload(JavaVM *vm) {
std::cout << "*********Agent_OnUnload**********\n"; }
代码编写完之后生成项目:

这里注意下,生成的本地库根据需要选择生成X86和X64版本,我们这里选择生成的是X64版本。生成的文件既有dll又有lib:

这两个文件都可以使用,我们这里选择使用dll文件。
下一步我们编写一个java的main方法,然后在启动jvm时加载我们的本地库:


运行结果如下:

调用了Agent_OnLoad函数和Agent_OnUnload函数,因为Agent_OnLoad和Agent_OnAttach函数在一个agent中只有一个会被调用,如果你希望在JVM启动时做些事情的话,就使用onload函数,如果希望有外部链接JVM时做一些工作的话就使用attach函数,unload函数在JVM关闭时调用。对于attach函数我们也可以在JVM运行时动态加载本地库并且调用。这需要用到jdk中的tools.jar包,在%JAVA_HOME%\lib目录中。举一个例子:
我们先写一个无限循环的小程序跑着

然后通过jps找到它的进程号

进程号为10748
下面是我们的代码
public class Test {
public static void main(String[] args) throws AgentLoadException, AgentInitializationException, IOException, AttachNotSupportedException {
attach();
}
public static void attach() throws AgentLoadException, AgentInitializationException, IOException, AttachNotSupportedException{
String pid = "10748";//java进程号
String agentPath = "C:\\Users\\DanteJ\\source\\repos\\agent\\x64\\Debug\\agent.dll";//本地库路径
System.out.println("attaching....pid="+pid);
VirtualMachine virtualMachine = VirtualMachine.attach(pid);//attach JVM
virtualMachine.loadAgentPath(agentPath);//加载本地库
virtualMachine.detach();//断开
}
}
下面是我们运行Loop的JVM打印的attach函数的运行结果

由此可见,我们可以动态的在已经运行的JVM中加载我们的本地代码。
下面我们再来看-javaagent
这里需要用到一个叫做premain的方法,它就像入口函数main方法一样是一个固定用法,其函数原型申明如下:
public static void premain(String agentArgs, Instrumentation ins)
我们编写一个测试类来作为演示
public class Agent {
public static void premain(String agentArgs, Instrumentation ins){
System.out.println("--------------javaagent-----------------");
}
}
然后编写MANIFEST.MF文件,必须要指定Premain-Class参数值
Manifest-Version: 1.0
Premain-Class: com.ideal.javaagent.Agent
然后将我们的测试项目打包成jar,然后下面代码执行时在JVM参数上添加-javaagent:C:\Users\DanteJ\Desktop\test.jar,其中test.jar是我们刚才打好的包。
public static void main(String[] args) throws AgentLoadException, AgentInitializationException, IOException, AttachNotSupportedException {
System.out.println("main");
}
运行结果如下

成功地在main方法执行前,执行了我们的jar包中的premain方法,有关premain方法中的java.lang.instrument.Instrumentation参数,提供了很多获取JVM参数的接口方法,这里
就不做深入了,如感兴趣可以自行查阅资料。
有关java agent的用法就介绍到这里,如果有什么解释不到或者有误的地方希望大神们指出。共同进步!!
java agent的更多相关文章
- 深入浅出Java探针技术1--基于java agent的字节码增强案例
Java agent又叫做Java 探针,本文将从以下四个问题出发来深入浅出了解下Java agent 一.什么是java agent? Java agent是在JDK1.5引入的,是一种可以动态修改 ...
- 探秘 Java 热部署三(Java agent agentmain)
前言 让我们继续探秘 Java 热部署.在前文 探秘 Java 热部署二(Java agent premain)中,我们介绍了 Java agent premain.通过在main方法之前通过类似 A ...
- 探秘 Java 热部署二(Java agent premain)
# 前言 在前文 探秘 Java 热部署 中,我们通过在死循环中重复加载 ClassLoader 和 Class 文件实现了热部署的功能,但我们也指出了缺点-----不够灵活.需要手动修改文件等操作. ...
- Java Agent初探——动态修改代码
用了一下午总算把java agent给跑通了,本篇文章记录一下具体的操作步骤,以免遗忘... 通过java agent可以动态修改代码(替换.修改类的定义),进行AOP. 目标: ? 1 为所有添加@ ...
- JVM插庄之二:Java agent基础原理
javaagent 简介 Javaagent 只要作用在class被加载之前对其加载,插入我们需要添加的字节码. Javaagent面向的是我们java程序员,而且agent都是用java编写的,不需 ...
- Java 调式、热部署、JVM 背后的支持者 Java Agent
我们平时写 Java Agent 的机会确实不多,也可以说几乎用不着.但其实我们一直在用它,而且接触的机会非常多.下面这些技术都使用了 Java Agent 技术,看一下你就知道为什么了. -各个 J ...
- java agent 详细介绍 -javaagent参数
java agent 详细介绍 简介 java agent是java命令的一个参数.参数 javaagent 可以用于指定一个 jar 包,并且对该 java 包有2个要求: 这个 jar 包的MAN ...
- 基于Java Agent的premain方式实现方法耗时监控(转),为了找到结论执行:premain在jvm启动的时候执行,所有方法前,会执行MyAgent的premain方法
Java Agent是依附于java应用程序并能对其字节码做相关更改的一项技术,它也是一个Jar包,但并不能独立运行,有点像寄生虫的感觉.当今的许多开源工具尤其是监控和诊断工具,很多都是基于Java ...
- java agent技术原理及简单实现
注:本文定义-在函数执行前后增加对应的逻辑的操作统称为MOCK 1.引子 在某天与QA同学进行沟通时,发现QA同学有针对某个方法调用时,有让该方法停止一段时间的需求,我对这部分的功能实现非常好奇,因此 ...
随机推荐
- ASP.NET没有魔法——ASP.NET MVC 直连路由(特性路由)
之前对Controller创建的分析中,知道了Controller的创建是有两个步骤组成,分别是Controller的类型查找以及根据类型创建Controller实例. 在查询Controller的类 ...
- JAVA To C++ Converter Cracked ( 破解版 )
JAVA To C++ Converter v17.10.2 Cracked by X-Cracker 简介 JAVA To C++是一款将JAVA代码或项目转换为 C++的工具 免费版本只每次只支持 ...
- zookeeper 笔记-Curator选举方案
Curator提供了两种选举方案:Leader Latch和Leader Election Leader Latch 随机从候选着中选出一台作为leader,选中之后除非调用close()释放lead ...
- Java运行时内存划分与垃圾回收--以及类加载机制基础
----JVM运行时内存划分----不同的区域存储的内容不同,职责因为不同1.方法区:被线程共享,存储被JVM加载的类的信息,常量,静态变量等2.运行时常量池:属于方法区的一部分,存放编译时期产生的字 ...
- await和async更多的理解
最近有不少网友提起await和async,呵呵,C# 5引进的语法糖. 这个语法糖还真不好吃,能绕倒一堆初学的朋友,在网上也有很多网友关于这块知识点的争论,有对有错,今天在这里把这个误区好好讲讲. 在 ...
- javascript 之作用域链-07
复习作用域 上一节我们说到作用域:是指变量可以访问的范围,他规定了如何查找变量,以及确定当前执行代码对变量的访问权限:也说到静态作用域即词法作用域,是在编译阶段决定变量的引用(由程序定义的位置决定,和 ...
- Java设计模式探讨之单例模式
单例模式是在平时的项目开发中比较常见的一种设计模式,使用比较普遍,网上的资料也是一抓一大把,小Alan也来凑凑热闹,为以后充实点设计模式相关的内容做个简单的开篇. 单例模式是一种创建对象的模式,用于产 ...
- linux学习(八)chmod、chown、umask、lsattr、chattr
一.权限位 权限位分为两个部分,第一个部分是谁的权限,第二部分是权限是多少.其中第一个部分一般分为:用户,用户组,其他用户.第二部分分为r:读权限,w:写权限,x:执行权限.可读,可写,可执行的权限, ...
- linux学习(二)linux配置网卡以及常见网络问题排查
实验环境环境:mac,vmware fusion 一.常用的虚拟机网络连接模式. NAT:推荐方式.它可以使你在切换网络环境(比如在工作中和家里)时,不需要修改虚拟主机的配置,而维持正常的上网功能. ...
- 暑假练习赛 006 A Vanya and Food Processor(模拟)
Description Vanya smashes potato in a vertical food processor. At each moment of time the height of ...