Java本地远程服务器debug调试详解

日常我们debug是经常用的,但是本地还好说,远程debug就有点难度,而且有时候必须要在预演,测试环境的服务器去debug,举个例子,需要https,公网,域名之类的,测试服务器这些有些是配置的,但是你自己本地开发肯定不会有这些,就需要你自己想办法了。

第一种情况就是你所用的是阿里云全家桶,或者是其他家的提供服务足够多的云服务商,你的公司又不差钱不墨迹,直接有啥用啥的话,实际上阿里云有一个toolkit的插件就可以,支持你镜像,kuberbets一大堆功能,他也可以做到远程调试。

远程连接服务器前置知识

但是如果没有去搞这些,甚至服务器都是自建的,那就要自己动手了。首先我们要理解一个概念JPDA(Java Platform Debugger Architecture)是Java平台调试体系结构,操作过程如下:

  • 1 本机和远程主机的两个 VM 之间使用 Debug 协议通过 指定的Socket 进行通信,传递调试指令和调试信息
  • 2 远程服务器作为被调试程序的远程虚拟机VM:作为 Debug 服务端,监听 Debug 调试指令。jdwp是Java Debug
    Wire Protocol的缩写
  • 3 本地调试程序的本地虚拟机VM:IDEA 中要先配置的 Remote Server,指定 Debug 服务器的Host:Port,以供
    Debug 客户端程序连接,这样服务调用就会调用到你本地,你就可以进行测试。

具体操作过程

配置IDEA中的remote,主要的配置如下:你要调用的module(就是项目入口的那个module),远程服务器地址,远程端口(这个远程端口不是服务器工程配置的端口,你可以理解为是JPDA的接口,用来监听远程服务debug)。

配置完上面主要的三个(毕竟这些都是你自己的,服务器多少,端口多少,那个项目都只有你知道),剩下的配置比较固定,比如通讯方式为socket,debug模式直接按照我的图抄就可以,attach是主动的获取debug的服务调用,listen是被动的,我一般是选择主动attach的,这样测试或者别人调起我debug的服务都会在我idea中展示出来,跟本地启动debug一样。
在这里插入图片描述
配置远程服务器启动
由于我的是SpringBoot工程,服务器用的是Jenkins,我需要的只是在Jenkins的启动参数上加上如下:

-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005

记住这里的端口号设置是你的idea,如果你实在记不清楚没把握,idea实际上在配置remote的时候已经给你生成好命令了。
在这里插入图片描述

启动远程服务器服务在启动本地远程debug

这里需要两个VM,本地的和远程的一个少不了,所以远程服务器启动项目这是一定的,但是本地怎么启动呢?

实际上你可以把第一步构建remote的过程,你可以理解为edit一个configuration,创建好了就会有一个项目在展示到启动项目那一块,如下:
在这里插入图片描述
只不过你会发现run是灰色的,debug是绿色可用的,不用怀疑,这压根也用不到run,直接点击debng按钮去调试就好了,主动一点,要不然配置也白配置,让项目走起来,这样本地的VM就可以和远程的VM通讯了,否则你本地没有VM怎么联调debug。



远程调试

1.1 使用特定JVM参数运行服务端代码

要让远程服务器运行的代码支持远程调试,则启动的时候必须加上特定的JVM参数,这些参数是:

-Xdebug -Xrunjdwp:transport=dt_socket,suspend=n,server=y,address=${debug_port}

其中的${debug_port}是用户自定义的,为debug端口,本例以5555端口为例。

本人在这里踩过一个坑,必须要说一下。在使用公司内部的自动化部署平台NDP进行应用部署时,该平台号称支持远程调试,只需要在某个配置页面配置一下调试端口号(没有填写任何IP相关的信息),并且重新发布一下应用即可。事实上也可以发现,上述JVM参数中唯一可变的就是${debug_port}。但是实际在本地连接时发现却始终连不上5555 的调试端口,仔细排查才发现,下面截取了NDP发布的应用所有JVM参数列表中与远程调试相关的JVM启动参数如下:

-Xdebug -Xrunjdwp:transport=dt_socket,suspend=n,server=y,address=127.0.0.1:5555

address设置为127.0.0.1:5555,表示将调试端口限制为本地访问,远程无法访问,这个应该是NDP平台的一个bug,我们在自己设置JVM的启动参数时也需要格外注意。

如果只是临时调试,在端口号前面不要加上限制访问的IP地址,调试完成之后,将上述JVM参数去除掉之后重新发布下,防范开放远程调试端口可能带来的安全风险。

1.2 本地连接远程服务器debug端口

1.1.1 配置

打开Intellij IDEA,在顶部靠右的地方选择”Edit Configurations…”,进去之后点击+号,选择”Remote”,按照下图的只是填写红框内的内容,其中Name填写名称,这里为remote webserverhost为远程代码运行的机器的ip/hostnameport为上一步指定的debug_port,本例是5555。然后点击Apply,最后点击OK即可。
在这里插入图片描述

1.1.2 本地IDEA启动debug模式

现在在上一步选择”Edit Configurations…”的下拉框的位置选择上一步创建的remote webserver,然后点击右边的debug按钮(长的像臭虫那个),看控制台日志,如果出现类似“Connected to the target VM, address: ‘xx.xx.xx.xx:5555’, transport: ‘socket’”的字样,就表示连接成功过了。我这里实际显示的内容如下:

Connected to the target VM, address: '10.185.0.192:15555', transport: 'socket'

1.1.3 设置断点,开始调试

远程debug模式已经开启,现在可以在需要调试的代码中打断点了,比如:
在这里插入图片描述

如图中所示,如果断点内有√,则表示选取的断点正确。

现在在本地发送一个到远程服务器的请求,看本地控制台的bug界面,划到debugger这个标签,可以看到当前远程服务的内部状态(各种变量)已经全部显示出来了,并且在刚才设置了断点的地方,也显示了该行的变量值。

在这里插入图片描述

备注:需要注意的是,用于远程debug的代码必须与远程部署的代码完全一致,不能发生任何的修改,否则打上的断点将无法命中,切记切记。

远程调试原理

Java远程调试的原理是两个VM之间通过debug协议进行通信,然后以达到远程调试的目的,两者之间可以通过socket进行通信;

我们知道,Java 程序都是运行在 Java虚拟机上的,我们要调试 Java程序,事实上就需要向 Java 虚拟机请求当前运行态的状态,并对虚拟机发出一定的指令,设置一些回调等等,那么Java的调试体系,就是虚拟机的一整套用于调试的工具和接口。

对于 Java 虚拟机接口熟悉的人来说,您一定还记得 Java 提供了两个接口体系:

  • JVMPI(Java Virtual Machine Profiler Interface)
  • JVMDI(Java Virtual Machine Debug Interface)

JPDAJava 平台调试体系)模块层次:
在这里插入图片描述

模块层次编程语言作用
JVMTI底层 `C`获取及控制当前虚拟机状态
JDWP中介层C定义JVMTIJDI交互的数据格式
JDI高层C提供JavaAPI来远程控制被调试的虚拟机

举个例子:客户端(ideaeclipse 等)之所以可以进行调试,是由于客户端 和 服务端(程序端)进行了 socket 通信,通信过程如下:

  1. 先建立起了 socket连接
  2. 将断点位置创建了断点事件通过 JDI 接口传给了 服务端(程序端)的 VMVM 调用 suspendVM 挂起
  3. VM挂起之后将客户端需要获取的 VM 信息返回给客户端,返回之后 VM resume 恢复其运行状态
  4. 客户端获取到VM返回的信息之后可以通过不同的方式展示给客户;

换句话说,通过JPDA这套接口,我们就可以开发自己的调试工具

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/554771.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux “ll“ 命令详解

“ls -l” “ls -al” ll 用来查询当前目录下文件及目录的详情 1.第一位文件类型 普通文件 , d 目录文件,I 链接文件,p 管理文件, b 块设备文件, c 字符设备文件, s 套接字文件 2.文件属性 第一部分表示文…

SpringBoot项目jar发布获取jar包所在目录路径

//第一种File path new File(ResourceUtils.getURL("classpath:").getPath());if(!path.exists()) path new File("");System.out.println(path.getAbsolutePath());//第二种System.out.println(System.getProperty("user.dir"));//第三种Stri…

路径classpath,classpath*,以及file:

./ 当前目录 …/上一层目录 /是根目录 1. classpath : 类路径,指的是编译后的字节码文件存储路径,一般为target目录下的classes目录(java项目),在web项目中指的是WEB-INF下的classes目录。实际上,两者其实…

到底什么时候该使用MQ?

一、缘起 一切脱离业务的架构设计与新技术引入都是耍流氓。 引入一个技术之前,首先应该解答的问题是,这个技术解决什么问题。 就像微服务分层架构之前,应该首先回答,为什么要引入微服务,微服务究竟解决什么问题&…

Java中ByteArrayInputStream和ByteArrayOutputStream用法详解

Java中ByteArrayInputStream和ByteArrayOutputStream用法详解 这篇文章主要介绍了Java中ByteArrayInputStream和ByteArrayOutputStream用法详解, ByteArrayInputStream 的内部额外的定义了一个计数器,它被用来跟踪 read() 方法要读取的下一个字节 Byte…

Java中的Base64详解

详解Java中的Base64原理跟用法 简介 ​ Base64编码,是我们程序开发中经常使用到的编码方法。它是一种基于用64个可打印字符来表示二进制数据的表示方法。它通常用作存储、传输一些二进制数据编码方法, 也是MIME(多用途互联网邮件扩展,主要用…

Java程序执行Linux命令

java程序中要执行linux命令主要依赖2个类:Process和Runtime 首先看一下Process类: ProcessBuilder.start() 和 Runtime.exec 方法创建一个本机进程,并返回 Process 子类的一个实例, 该实例可用来控制进程并获得相关信息。Proces…

ImageIO类说明

最近的项目中遇到ImageIO,因此记录下这个类的用法 一、ImageIO: 这个类中的方法都是静态方法,可以用来进行简单的图片IO操作 1、读入的三种方法 public static BufferedImage read(File input) File file new File("/Users/xixi/Docum…

java:图像(BufferedImage)色彩空间转换(灰度)暨获取图像矩阵数据byte[](sRGB/gray)

ColorConvertOp java.awt.image包下面有个类java.awt.image.ColorConvertOp,类名直译就是”颜色转换操作”。 顾名思义,它的作用就是将一个色彩空间(color space)的图像转换为另一个色彩空间的图像。有了这个神器我们就能轻易的将一张彩色图你像转换成灰度(gray)或其他色彩空间…

MyBatis-Plus updateById方法更新不了空字符串/null解决方法

最近遇到了Mybatis-Plus updateById(),更新某一个字段为null,却发现没有更新成功。记录一下 一、简介 因为最近在忙项目,好久都没有更新博客,最近在项目中刚好遇到一个问题,就是在使用MyBatis-Plus updateById&#…

Java 分割字符串的方法String.split()底层原理与使用

文章目录split()底层原理1.举例说明2.split源码分析3.API原解4.regex参数API原解5.limit参数介绍6.结果的验证7.此方法的使用split方法的使用split用法分析参数解释—regex参数解释—limit不同limit值的情况下的split结果验证扩展split()底层原理 1.举例说明 1.最普通的用法 …

HttpClient使用和详解

文章目录一、关于HttpClient二、HttpClient使用步骤详解1、创建一个HttpClient对象A、HttpCLientConnectionManagerB、HttpRoutePlannerC、RequestConfig2、创建一个Request对象3、执行Request请求4、处理response1)关闭和entity相关的content stream2)关…

你还在 Docker 中跑 MySQL?

容器的定义:容器是为了解决“在切换运行环境时,如何保证软件能够正常运行”这一问题。 目前,容器和 Docker依旧是技术领域最热门的词语,无状态的服务容器化已经是大势所趋,同时也带来了一个热点问题被大家所争论不以&…

使用mybatis-plus来自定义排序

需求&#xff1a; 先时间升序排序&#xff0c;相同的时间在按状态排序&#xff0c;状态的顺序为1 在线 4 潜伏 2 隐身 3 离开&#xff0c;状态相同在按姓名升序排序对排序好的数据进行分页运用mybatis-plus中QueryWrapper 1.导入依赖 <dependencies><dependency>…

Postman实现接口测试(附项目实战)

文章目录Postman实现接口测试1.Postman介绍和安装2. Postman安装2.1 安装方式2.2 安装步骤3. Postman入门示例Postman基本用法Postman高级用法1. 管理用例2. Postman断言3. 全局变量与环境变量5. Postman关联6. 批量执行测试用例7. 读取外部文件实现参数化Postman测试报告目标项…

Postman 使用教程详解

Postman页面 2、新建一个项目 直接点击左边栏上面的添加目录图标来新增一个根目录&#xff0c;这样就等于新建了一个项目&#xff0c;我们可以把一个项目或一个模块的用例都存放在这个目录之下&#xff0c;并且在根目录之下我们还可以在建立子目录来进行功能用例的细分&#…

Springboot dubbo @Service @Transactional 无法提供服务或者无法提供事务的解决办法

问题场景&#xff1a; 今天在springboot中集成spring事务的时候&#xff0c;遇到了一个大坑。如果&#xff08;springbootdubbo&#xff09;中添加 Service、Transactional 两个注解的时候&#xff0c;就不能进行dubbo服务注册了。 解决历程&#xff1a; 1&#xff0c;先是在…

什么是 serialVersionUID ? 序列化对象时必须提供 serialVersionUID 吗?

什么是 serialVersionUID &#xff1f; 序列化对象时必须提供 serialVersionUID 吗&#xff1f; 1&#xff0c;什么是 serialVersionUID &#xff1f; 顾名思义&#xff0c;serialVersionUID是序列化版本号。所有可序列化的类&#xff0c;都有一个静态serialVersionUID属性&a…

谈Java集合类的toArray()的小bug

谈Java集合类的toArray()的小bug toArray()方法 它的作用是将集合转换成数组。但是这个方法有一个弊端&#xff0c;当toArray()方法使用不当时会产生ClassCastException&#xff08;类转换异常&#xff09; public static void main(String[] args) {List<Integer> li…

Dubbo系统里面MultipartFile文件传输问题Dubbo文件上传/传输服务

今天遇到一个问题&#xff0c;在Controller 层里面&#xff0c;直接使用MultipartFile 来接收上传的图片&#xff0c;遇到几个坑。 一、在spring配置文件里面配置文件上传 <!--文件上传--><bean name"multipartResolver"class"org.springframework.web…