在java代码开发过程中,有些测试环境的bug,通过java  jdwp( Java Debug Wire Protocol)进行远程调试。jdwp定义了调试器(debugger)和被调试的 Java 虚拟机(target vm)之间的通信协议。

Target vm 中运行着我们希望要调试的程序,它与一般运行的 Java 虚拟机没有什么区别,只是在启动时加载了 Agent JDWP 从而具备了调试功能。而 debugger 就是我们熟知的调试器,它向运行中的 target vm 发送命令来获取 target vm 运行时的状态和控制 Java 程序的执行。Debugger 和 target vm 分别在各自的进程中运行,他们之间的通信协议就是 JDWP。

JDWP 与其他许多协议不同,它仅仅定义了数据传输的格式,但并没有指定具体的传输方式。这就意味着一个 JDWP 的实现可以不需要做任何修改就正常工作在不同的传输方式上

Target vm 端,JDWP 模块必须以 Agent library 的形式在 Java 虚拟机启动时加载,并且它必须通过 Java 虚拟机提供的 JVMTI 接口实现各种 debug 的功能,所以必须使用 C/C++ 语言编写。而 debugger 端就没有这样的限制,可以使用任意语言编写,只要遵守 JDWP 规范即可。JDI(Java Debug Interface)就包含了一个 Java 的 JDWP debugger 端的实现,JDK 中调试工具 jdb 也是使用 JDI 完成其调试功能的。

JDWP的更深介绍参考: https://www.jianshu.com/p/134bd5b913c5

JDWP使用

服务器端

服务器端需要加载jdwp,设置方式如下:

CMD java -Djava.security.egd=file:/dev/./urandom $TRACK -jar $JAVA_OPTS -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=9052 data-assets-biz.jar

需要加载jdwp agent。

参数说明:

  • transport:指定了调试数据的传送方式
  • dt_socket:是指用SOCKET模式
  • address: 端口或者HOST:PORT
  • server=y/n VM 是否需要作为调试服务器执行。
  • suspend=y/n 在调试客户端建立连接之后是否挂起。

本地端

IDEA 配置调试。

进行断点调试时,远程服务器会挂起。

Agent

jdwp使用的是agent技术。在JDK1.5以后,可以使用agent技术构建一个独立于应用程序的代理程序(即为Agent),用来协助监测、运行甚至替换其他JVM上的程序。使用它可以实现虚拟机级别的AOP功能。

Agent分为两种,一种是在主程序之前运行的Agent,一种是在主程序之后运行的Agent(前者的升级版,1.6以后提供)。

主程序

package study;public class AgentTest {public static void main(String[] args) {System.out.println("this is main process");}
}

在主程序运行之前的代理程序

1、编写agent程序

package agent;import java.lang.instrument.Instrumentation;public class TestAgent {public static void premain(String agentArgs, Instrumentation ins){System.out.println("premain start...");System.out.println(agentArgs);}
}

2、配置MANIFEST.MF

<build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-jar-plugin</artifactId><version>3.2.0</version><configuration><archive><manifest><addClasspath>true</addClasspath></manifest><manifestEntries><Premain-Class>agent.TestAgent</Premain-Class></manifestEntries></archive></configuration></plugin></plugins></build>

3、主程序加载agent程序

java  -cp ./agent-test-0-1.0.jar   -javaagent:./agent-test-pre-1.0.jar=x study.AgentTest

输出:

premain start...
x
this is main process

agent详解

参数 javaagent 可以用于指定一个 jar 包,并且对该 java 包有2个要求:

  1. 这个 jar 包的MANIFEST.MF 文件必须指定 Premain-Class 项。
  2. Premain-Class 指定的那个类必须实现 premain()方法。

重点就在 premain 方法,也就是我们今天的标题。从字面上理解,就是运行在 main 函数之前的的类。当Java 虚拟机启动时,在执行 main 函数之前,JVM 会先运行 -javaagent 所指定 jar 包内 Premain-Class 这个类的 premain 方法,其中,该方法可以签名如下:

1.public static void premain(String agentArgs, Instrumentation inst)
2.public static void premain(String agentArgs)

JVM 会优先加载 1 签名的方法,加载成功忽略 2,如果1 没有,加载 2 方法。

在主程序运行之后的代理程序

premain 只能在类加载之前修改字节码,类加载之后无能为力,只能通过重新创建ClassLoader 这种方式重新加载。而 agentmain 就是为了弥补这种缺点而诞生的。简而言之,agentmain 可以在类加载之后再次加载一个类,也就是重定义,你就可以通过在重定义的时候进行修改类了,甚至不需要创建新的类加载器,JVM 已经在内部对类进行了重定义。

但是这种方式对类的修改是由限制的,对比原来的老类,由如下要求:

1.父类是同一个;
2. 实现的接口数也要相同;
3. 类访问符必须一致;
4. 字段数和字段名必须一致;
5. 新增的方法必须是 private static/final 的;
6. 可以删除修改方法;

可以看的出来,相比较重新创建类加载器,限制还是挺多的,最重要的字段是无法修改的。因此,使用的时候要注意。

但是,agentmain 还有一个强大的特点,就是目标程序什么都不需要管,就能够被代理。还记得 premain 是如何使用的吗?需要在目标应用启动的时候增加 -javaagent 参数。虽说没有侵入性,但相比 agentmain 而言,还是有侵入性的,毕竟 agentmain 什么都不要。目标程序独立运行,什么都不用管。

1、编写agent程序

package agent;import java.lang.instrument.Instrumentation;public class TestAgent4 {public static void agentmain(String agentArgs , Instrumentation inst){System.out.println("load agent after main  run.args=" + agentArgs);Class<?> [] classes = inst.getAllLoadedClasses();for(Class<?> c :classes){System.out.println(c.getCanonicalName());}System.out.println("agent run complete."  );}
}

2、配置MANIFEST.MF

<build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-jar-plugin</artifactId><version>3.2.0</version><configuration><archive><manifest><addClasspath>true</addClasspath></manifest><manifestEntries><Agent-Class>agent.TestAgent4</Agent-Class></manifestEntries></archive></configuration></plugin></plugins></build>

3、主程序加载agent程序

package study;public class AgentTest {public static void main(String[] args) {System.out.println("this is main process");List<VirtualMachineDescriptor> list = VirtualMachine.list();for (VirtualMachineDescriptor vmd : list) {if (vmd.displayName().endsWith("AccountMain")) {VirtualMachine virtualMachine = VirtualMachine.attach(vmd.id());virtualMachine.loadAgent("F:\\agent-test-post-1.0.jar");System.out.println("ok");virtualMachine.detach();}}}
}

需要先attach到一个VM,再加载agent。不是把agent加载到本VM。

输出:

MANIFEST.MF参考:https://blog.csdn.net/demon7552003/article/details/106568285

Java Agent相关推荐

  1. 写那么多年Java,还不知道啥是Java agent 的必须看一下!

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试文章 作者信息:张帅,花名洵澈,国际化中台事业部高级开发工程师,负责物流 ...

  2. 我的天,你工作5年了,连Java agent都不知道...

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试文章 # 引言 在本篇文章中,我会通过几个简单的程序来说明 agent ...

  3. java实现扫地agent_如何实现java agent?分享java agent的使用案例

    java agent如何实现?1.实现java agent需要实现premain方法:2.必须在MANIFEST.MF文件中有Premain-Class. 在字节码这个层面对类和方法进行修改的技术,能 ...

  4. 说实话,你工作5年,不知道什么是Java agent技术,让我很吃惊...

    注:本文定义-在函数执行前后增加对应的逻辑的操作统称为MOCK. 引子 在某天与QA同学进行沟通时,发现QA同学有针对某个方法调用时,有让该方法停止一段时间的需求,我对这部分的功能实现非常好奇,因此决 ...

  5. 通过使用Byte Buddy,便捷地创建Java Agent

    Java agent是在另外一个Java应用("目标"应用)启动之前要执行的Java程序,这样agent就有机会修改目标应用或者应用所运行的环境.在本文中,我们将会从基础内容开始, ...

  6. idea git 过滤target_IDEA + maven 零基础构建 java agent 项目

    Java Agent(java 探针)虽说在 jdk1.5 之后就有了,但是对于绝大多数的业务开发 javaer 来说,这个东西还是比较神奇和陌生的:虽说在实际的业务开发中,很少会涉及到 agent ...

  7. Java agent初探

    点击上方"朱小厮的博客",选择"设为星标" 后台回复"加群"获取公众号专属群聊入口 来源:阿里巴巴中间件 在本篇文章中,我会通过几个简单的程 ...

  8. java 字节码增强原理_深入浅出Java探针技术1--基于java agent的字节码增强案例

    Java agent又叫做Java 探针,本文将从以下四个问题出发来深入浅出了解下Java agent 一.什么是java agent? Java agent是在JDK1.5引入的,是一种可以动态修改 ...

  9. JVM插桩之二:Java agent基础原理

    Javaagent只要作用在class被加载之前对其加载,插入我们需要添加的字节码. Javaagent面向的是我们java程序员,而且agent都是用java编写的,不需要太多的c/c++编程基础, ...

  10. java agent技术原理及简单实现

    注:本文定义-在函数执行前后增加对应的逻辑的操作统称为MOCK 1.引子 在某天与QA同学进行沟通时,发现QA同学有针对某个方法调用时,有让该方法停止一段时间的需求,我对这部分的功能实现非常好奇,因此 ...

最新文章

  1. 【杂谈】裸辞一年后,分享一下我的心态
  2. CowNew开源-sql解析引擎和cownewsql阶段成果汇报
  3. 如何给Typora安装主题
  4. tensorflow 之 ValuError: At least two variables have the same name: bottom/bn1/beta_power0 等
  5. git stash命令的用法
  6. 神奇的python(三)之Python扩展C/C++库(C转换为Python)
  7. [乱弹琴]关于2的讨论
  8. 动手学深度学习 v2 PDF版本
  9. DOS命令和linux
  10. 微信小程序图片上传至mysql数据库
  11. for(int i = 0;i 10;i++)和int i;for(i = 0;i 10;i++)
  12. 谷歌浏览器崩溃之后卸载无法重装的解决方法
  13. word中插入的图片会覆盖文字
  14. Java五子棋(局域网)
  15. win10蓝牙功能不见了_Win10 2004更新了什么?新功能新特性汇总
  16. @Before和@After的区别
  17. 正则表达式(附匹配手机号和HTML标签)
  18. win系统快捷键大全
  19. 爬虫实战1:爬取糗事百科段子
  20. 朴素贝叶斯 实现 垃圾邮件分类

热门文章

  1. VS2010 IDE新特性随笔
  2. 《面向对象软件工程》笔记(一)
  3. 【Redis学习】Redis实现分布式锁
  4. How to mount HFS EFI on macOS
  5. 一次完整的http的请求过程与https的实现
  6. 版本管理工具Git(2)git的使用
  7. TID大会学习心得之敏捷软件架构-微服务
  8. windows7旗舰版系统自带组件IIS搭建ftp
  9. VMM2012应用指南之3-安装VMM2012
  10. 计算机组成原理第4章,计算机组成原理-第4章总结.doc