吾志所向,一往无前;愈挫愈奋,再接再厉

IDEA远程开发

Posted on By Eironn

IDEA远程开发

具体原理是把程序的编译和运行放在服务器上,通过本机和服务器建立连接后实时传说信息以及日志的方式来实现将耗费资源的行为放在服务器上。

远程模式分为远程开发和远程调试两种。

  • 远程开发目前只有CLion,是一款Jetbrains出品的C和C++的开发工具,这里不做研究。
  • 远程调试针对的所有的Jetbrains产品,通过一些运行脚本以及agentlib等参数来实现。

优缺点对比

远程调试每次修改完代码后都是经过脚本把代码同步到服务器,然后执行maven的打包,然后运行jar/war包后,利用agentlib,实现本地的调试功能,因此实时性不是很好。

远程开发具有远程调试的所有功能,并且实时性更好,不需要每次打包,但是不支持Java,并且技术可能不是特别完善,服务器会吃更多的内存。(个人根据一些文章的猜测而已)

因此,下面讲解的是远程调试


一. 准备工作

  1. 环境介绍:

    我是用的是两台Ubuntu18.04系统,一台我自己的笔记本作为开发机,一台公司的台式机作为服务器。

  2. 配置ssh免密登录

    客户端机器,下面我成为A,可以免密登录服务端机器,下面我成为B。

    具体可以自己搜索教程这里不做展开。

  3. 准备启动脚本

    文件名字为manage.sh,启动方式为./manage.sh restart/start/stop server.jar dev

    最后参数是为了区分不同环境的,默认不传的话就是dev环境

    #!/bin/bash
    # usage demo:sh manage.sh restart config-server.jar
    ## 将jar 和配置文件放在同一目录下
       
    DATE=$(date +"%Y-%m-%d %H:%M:%S")
    GREP_EXP="grep|manage.sh|tail|more|less|cat|vim|log"
       
    ACTIVEFILE=dev
       
    ## 将操作记录一下 
    ## eg:--- 2019-08-21 12:31:48 ---用户: root --- 命令:  restart material-service
    echo "--- $DATE ---"用户": $(whoami) --- "命令": $basename $@" >> .operate_history
       
    server_status(){
    	SERV_FILE=$1
    	SERV_NAME=$(basename $SERV_FILE .jar)
    	## 文件不存在直接返回
    	if [ ! -f "$SERV_FILE" ]; then 
    		echo "$SERV_FILE not exist!!!"
    		exit 1
     	fi 
       	
    	NUM=$(ps -ef |grep "$SERV_NAME" |egrep -v "$GREP_EXP" |wc -l)
    	if [ $NUM -gt 0 ];then
    		echo "service:$SERV_NAME (UP) counts : $NUM "
    		return 1
    	else
    		echo "service:$SERV_NAME (DOWN) counts : $NUM "
    		return 0
    	fi
    }
       
    server_stop(){
    	SERV_FILE=$1
    	SERV_NAME=$(basename $SERV_FILE .jar)
    	server_status $SERV_FILE
    	if [ $? -eq 0 ];then
    		echo "service:$SERV_NAME is already down!"
    	else
    		#ps -ef |grep java |egrep "$SERV_NAME"| egrep -v "$GREP_EXP" |awk '{print $2}' |while read i ; do kill -9 $i; done
    		ps -ef | grep $SERV_NAME | egrep -v "$GREP_EXP" | awk '{print $2}' | xargs kill -9
    		echo "service:$SERV_NAME is killing ...!"
    		for  i in {1..10} ; do echo ... && sleep 0.5 ; done
    		server_status $SERV_FILE
    		if [ $? -eq 0 ];then
    			echo "service:$SERV_NAME killed ok !"
    		else
    			echo "service:$SERV_NAME killed fail ,please check !"
    			exit 1
    		fi
    	fi
    }
       
    server_start(){
    	SERV_FILE=$1
    	ENVIR=$2
       
    	## 给定了环境,使用给定的
            if [ !-z $ENVIR ]
            then
                    echo "默认dev环境"
            else
                    echo "使用$ENVIR环境"
                    ACTIVEFILE=$ENVIR
            fi
       
    	## 去除后缀 .jar
    	SERV_NAME=$(basename $SERV_FILE .jar)
       
    	server_status $SERV_FILE
       
    	if [ $? -eq 1 ];then
    		echo "service:$SERV_NAME is already up!"
    	else
    		## 创建 log 日志文件夹
    		if [ ! -d logs ];then
    			mkdir -p logs
    		fi
       
    		echo "java -server \
    		-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005 \
    		-Dspring.profiles.active=${ACTIVEFILE} \
    		-Xmx512m -Xms256m -Xmn256m -XX:+UseG1GC -XX:+DisableExplicitGC \
    		-Duser.timezone=GMT+8 \
    		-jar ${SERV_FILE} \ "
    	    ## 启动
    		java -server \
    		-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005 \
    		-Dspring.profiles.active=${ACTIVEFILE} \
    		-Xmx512m -Xms256m -Xmn256m -XX:+UseG1GC -XX:+DisableExplicitGC \
    		-Duser.timezone=GMT+8 \
                    -jar  ${SERV_FILE} \
    		# > logs/${SERV_NAME}.log 2>&1 &
    		# > /dev/null 2>&1 &
    		#-jar  ${SERV_FILE} > logs/${SERV_NAME}.log 2>&1 &
       
    		echo "service:$SERV_NAME started!"
    	fi
    }
       
    case $1 in
    status)
    	SERV_FILE=$2
    	server_status $SERV_FILE
    	;;
    stop)
    	SERV_FILE=$2
    	server_stop $SERV_FILE
    	;;
    start)
    	SERV_FILE=$2
    	ENVIR=$3
    	server_start $SERV_FILE $ENVIR
    	;;
    restart)
    	SERV_FILE=$2
    	ENVIR=$3
    	server_stop $SERV_FILE
    	server_start $SERV_FILE $ENVIR
    	;;
    *)
    	echo 'help'
    	;;
    esac
    

二. 客户端中的IDEA的配置

需要两个external,一个是同步代码,另外一个是使用maven打包以及利用agentlib实现远程调试功能

使用的两个程序一个是rsync(同步项目),一个是ssh,rsync不知道是否是Linux独有的?是的话可以换别的

打开Configuration,Add New Configuration,选择remote,默认端口5005,可以不改,改的话manage.sh也要一起改。

配置1

新增代码同步External,配置如下

Program:  rsync
Arguments: 
-avc
/home/invlong/tools/project/java-k12-server/
root@10.19.0.16:/invlong/project/java-k12-server

新增启动项目External,配置如下

如果要切换环境,需要改这个,最后的dev改成test或者别的

Program: ssh
Arguments: 
root@10.19.0.16 sh -c 'cd /invlong/project/java-k12-server && mvn clean package -e -U -Dmaven.test.skip=true && sudo /invlong/project/manage.sh restart /invlong/project/java-k12-server/target/java-k12-server.jar dev'

配置2

配置3

三. 遇到的问题

  1. sh调用命令和直接在terminal中是不一样的,需要特殊操作,如下。
# 在我的电脑terminal中执行mvn -version是可以的,但是通过sh执行报错,因为sh走的是/user/bin下的
sh: 1: mvn: not found
# 解决方法,进行软挂载
ln -s /invlong/tools/maven/apache-maven-3.2.3/bin/mvn /usr/bin/mvn
# java环境原来指向的是root环境的,因此要先执行删除,再新增
rm -rf /user/bin/java
ln -s /invlong/tools/java/jdk/jdk1.8.0_201/bin/java /usr/bin/java

  1. 连接远程服务器使用的是非root用户,导致权限问题

    主要是-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005这句需要root权限,我没深入研究,直接改为root用户了。

  2. 使用manage.sh启动时,开始用的是nohup启动,这样没办法实时返回信息给我A,并且会导致连接断开。