本文整体结构如下:
1. 先大致说明下需求:需要在idea中调试可执行jar包的main方法,
2. 然后给出解决方法
3. 说下我之前用的其他方法
4. 说下如何使用java相关的编译命令(javac)、打包命令(jar)生成本文中的可执行jar包
一、需求说明
如图所示,比如我有一个java项目(ProjectMgmtSystem),目前依赖了一个jar包(mypro.jar) 。
该可执行jar包通常会有一个main方法,以及一大堆的方法以及相关类来实现特定的逻辑。这里虽然做了简化,但依然能体现问题的本质,比如我需要对main方法打断点,一步步测试下代码的执行逻辑。
现在我就想在idea中,对这个jar包里的main方法进行调试。当然有人会说不一定非得使用这种方法,在这里我就是有这个需求,我想采用最直接的方式来测这个jar包里的逻辑(其他方法一会我留到后面再说)
二、解决办法
我一开始在网上找了下,没发现什么有价值的信息。最后回归到问题本身,我就是要测一个main方法,然后我就看了下正常情况下可以点debug的main方法配置是怎样的,然后依葫芦画瓢,也创建了一个配置,发现竟然可以用。配置如下:
按照以上步骤操作后,再次点击debug,就会发现竟然可以调试了。效果如下:
三、其他方法
方法一:
一般在使用可执行jar包(以下均以mypro.jar为例)的时候,我们都是在命令行里直接敲 java -jar mypro.jar
这是最原始的方法,只能看看结果,没有办法去跟踪代码的运行逻辑。
方法二:
还有一个办法,自己在项目里引入mypro.jar,自己创建一个类,然后手动去调用jar包里的main方法(如果只想看里面某个方法的运行逻辑,比如getInfo,就需要用下反射来调用)。
四、如何使用java相关的编译命令(javac)、打包命令(jar)生成本文中的可执行jar包
网上有关如何用idea导出jar包的文章很多也很具体,我就不再重复了。
但是关于如何编译并打包jar说的不是很明确,我写这篇博文之前,也花费了一点时间来进行验证(毕竟做开发平时真正需要用javac,jar命令的机会很少),下面简单记录下操作过程。
因为代码整体比较简单,整个jar包里就一个文件,我就不想去再新建一个项目了,然后在idea中导出jar包;还是选择手动创建文件夹,写了一个Demo类,然后执行几条命令编译出jar包
代码目录结构如下:
D:\javapro下面有一个src目录,
Demo.java代码如下:
package com.kittycoder;
/**
* Created by shucheng on 2019-10-24 下午 20:26
*/
public class Demo {
public static void main(String[] args) {
Demo demo = new Demo();
System.out.println(demo.getInfo());
}
private String getInfo() {
return "Hello World!";
}
}
首先是将.java编译成为.class文件,
我首先想到的是这样写,但是这样一会还得来回切换目录,我想起javac有一个sourcepath选项,它可以让你在项目源码目录(D:\javapro\src\com)的上一层目录(D:\javapro\src)执行javac进行编译
当然,你也可以在D:\javapro这个目录下编译,
再验证下能否正常运行,一切正常
然后,将class文件打包到jar包中
再来验证下,可以正常运行
所以,建完文件夹,写好代码以后,我只需要进到D:\javapro\src目录下,执行cmd命令:
rem 编译并生成jar包
javac -sourcepath . com/kittycoder/Demo.java&&jar -cvfe mypro.jar com.kittycoder.Demo com/kittycoder/Demo.class
rem 验证jar包能否正常运行
java -jar mypro.jar
附注:
Test.java:
package com;
import com.kittycoder.Demo;
import java.lang.reflect.Method;
/**
* Created by shucheng on 2019-10-24 下午 21:11
*/
public class Test {
public static void main(String[] args) throws Exception {
Demo demo = new Demo();
// System.out.println(demo.getInfo()); // 编译不通过,无法直接访问私有方法
Method getInfoMethod = Demo.class.getDeclaredMethod("getInfo");
getInfoMethod.setAccessible(true);
System.out.println(getInfoMethod.invoke(demo));
}
}