Java 远程 debug
本地 Debug 很容易, 那么远程 debug 是怎么做的, 又有哪些坑呢?
一般应用程序 debug
这里的一般应用程序就是一个 main 函数, 不是 web 应用程序. 首先, 这个应用在远程某主机上能运行, 只要启动的时候, 添加远程 debug 参数就可以了.
比如有如下代码, 为了让它慢一点可以 debug, 加入了一个循环和睡眠:
public class Debugger {
public int loop(int count) {
int sum = 0;
for (int i = 0; i < count; i++) {
sum += i;
try {
System.out.println(i + "/" + count + " current sum: " + sum);
Thread.sleep(5L);
} catch (Exception e) {
e.printStackTrace();
}
}
return sum;
}
public static void main(String[] args) {
Debugger debugger = new Debugger();
int sum = debugger.loop(10000);
System.out.println("sum is " + sum);
}
}
在远程编译, 启动, 并且加入监听端口为了方便远程debug:
$ javac Debugger.java
$ java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=0.0.0.0:8000 Debugger
这里注意的是, 我们对于地址使用的是: 0.0.0.0:8000
, 有些地方你看到的直接是 8000
端口, 没有主机ip部分. 这会导致这个端口只是开在 localhost, 你如果使用 netstat
查看, 能看到 8000
端口是开着的, 但是远程无法连接.
在远程可以使用 telnet
或者 curl
来测试这个端口是不是可以远程连接. 但是注意这个端口只能有一个远端能连接成功, 假如你已经使用 curl 连接上, 那么你远端的其它 IDE 就不能连接了.
我本地的 Eclipse 连接的过程是: 在菜单 Run 里面选择 Debug Configurations, 然后新建 Remote Java Application, 然后输入远程的 IP 和 端口. 如下:
连接后, Eclipse 会显示连接成功, 然后点击 暂停, 就会暂停远程的应用了.
debug 远程 tomcat 里面的应用
在 Tomcat 的 catalina.sh 里面, 添加如下环境变量设置:
export JPDA_ADDRESS=0.0.0.0:8000
export JPDA_TRANSPORT=dt_socket
然后启动时候, 添加 jdpa
参数, 就可以了
./catalina.sh jpda start
debug 远程基于 Spring boot 的应用
其实 Spring boot 是做的 fat jar, 它的远程debug 方式跟一般的应用是一样的, 就是在启动参数里面加上. 例子如下:
java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=0.0.0.0:8000 -jar myApp.jar
隧道技术
有时候远程机器隔着防火墙, 你不能直接连, 但是你可以通过 ssh
登录, 那么就可以用过隧道技术, 使用 ssh 做隧道, 然后远程 debug.
首先, 我们假设远程机器的 debug 开在 8000 端口上:
java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=0.0.0.0:8000 -jar myApp.jar
然后在本地机器上建立隧道:
ssh -L 5000:localhost:8000 user@remote_ip
这里的意思是: 在本地启动5000端口, 它所有的数据原封不动的转到远程 remote_ip 的8000 端口. 我们登录远程 remote_ip 的用户名是 user, 这里它会让你输入 ssh user 的密码. 连接成功后, 隧道建立.
这时候, 在本地和之前的一样, 只是把远程机器的ip 改成本地机器localhost, 端口改成 5000. 就能借助隧道进行远程 debug 了.