java agentlib jdwp,JAR文件格式 & JDWP远程调试

JAR文件是如何启动的?

SpringBoot构建的结果中,尝尝会以JAR文件的形式提供,众所周知,JAR文件本质上是一个特殊的压缩文件,这里我们创建一个简单的SpringBoot项目,使用Maven 或者Gradle 构建,然后解压,其内容格式如下:

├── BOOT-INF│   ├── classes│   │   ├── application.properties│   │   ├── com│   │   ├── static│   │   └── templates│   └── lib│   ├── classmate-1.5.1.jar| |—— 这里由于篇幅忽略一写第三方的依赖JAR│   └── tomcat-embed-websocket-9.0.33.jar├── META-INF│   └── MANIFEST.MF└── org└── springframework└── boot

可以很明显的看到,JAR中包含了第三方的JAR包,这显然使用默认的应用类加载器是无法加载编译生成的class的以及我们生成的目录classes中的的class文件的。

尝试查看 MAINFEST.MF 文件,其内容如下:

$ cat ./build/libs/springboot-0.0.1-SNAPSHOT/META-INF/MANIFEST.MFManifest-Version: 1.0Start-Class: com.zhoutao123.spring.springboot.SpringbootApplicationSpring-Boot-Classes: BOOT-INF/classes/Spring-Boot-Lib: BOOT-INF/lib/Spring-Boot-Version: 2.2.6.RELEASEMain-Class: org.springframework.boot.loader.JarLauncherMAINFEST.MF 文件的格式内容,可以参考: JAR 文件格式规范

Main-Class 指定了JVM 在运行JAR文件的是时候,所启动的类,这个类必须包含一个共有的静态的main方法,这也是为什么SpringBoot的在打包的时候,会将org.springframework.boot.loader 的包给放到最外层,这样,其启动类Launcher.class就可以正常的被加载到系统类加载器, 在其他位置的加载器中,系统类加载器无法加载的JAR文件或者BOOT-INFO/classes 文件下的 class文件,则使用自定义的类加载器加载。可以通过下面的代码验证,SpringBoot APP的启动类并不是系统类加载器加载,而是自定义的类加载器加载的。

@SpringBootApplicationpublic class SpringbootApplication {public static void main(String[] args) {System.out.println("当前类的加载器为:" + SpringbootApplication.class.getClassLoader());SpringApplication.run(SpringbootApplication.class, args);}}

请不要尝试在IDE中尝试验证,如果在IDE中运行的话,你可能得到的结果如下,这里因为在集成开发环境中运行,class文件是松散的保存在classPath目录中的,这时候并没有启动自定义的加载类,因为仍然是默认的系统类加载器加载。

当前类的加载器为:sun.misc.Launcher$AppClassLoader@18b4aac2

构建成新的JAR文件之后,使用 java -jar xxxx.jar 命令启动后,可以看到输出如下,分析可知,系统类加载器为 org.springframework.boot.loader.LaunchedURLClassLoader 这就是我们将要深入学习的SpringBoot的自定义类加载器。

当前类的加载器为:org.springframework.boot.loader.LaunchedURLClassLoader@5197848c

使用JDWP来远程调试

上面的JAR文件的类加载器是JVM启动的才会调用,在IDE中调试并不是使用SpringBoot的自定义类加载器加载,因此我们这里需要使用JDK的远程调试功能来调试代码。在命令行输入如下格式的语法命令,来启动JAR,这里不再对JDWP过多的赘述,有兴趣的可以在网上查一下。

java -agentlib:jdwp=transport=dt_socket, \server=y,suspend=y,address=9999 \-jar xxxx.jar

然后,在IDEA中,创建远程调试,信息如下:

58c7d5392e1e0cc7ec8be4630501ebb1.png

然后在Gradle依赖中添加 SpringBootLoader的依赖

implementation 'org.springframework.boot:spring-boot-loader'

或者Maven的pom文件中添加

org.springframework.bootspring-boot-loader

找到  JarLauncher 类添加断点,然后以Degbug模式启动在IDEA创建的远程调试,即可看到正确进入断点。

b5b87372a95e3e8081a80cb42111f69d.png

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值