资讯专栏INFORMATION COLUMN

本地实现Java远程热部署

mist14 / 496人阅读

摘要:热部署中间件阿里巴巴用户文档执行命令下载至新建的目录执行命令应用使用提供的命令来替换中的,而无需重启,从而实现热部署,当然就阿尔萨斯本身是提供命令,可以直接在内存中编译文件,但是自己试了几次失败了,所以,需要先在本地编译相关的文件,然

1.热部署中间件-arthas 阿里巴巴
1)用户文档:

https://alibaba.github.io/art...

2)执行命令:

mkdir -p /home/work/local/arthas-boot

3)下载arthas.jar 至 2)新建的目录

4)执行命令

touch hot_depoy.sh

2.应用

使用arthas提供的redefine命令来替换jvm中的class,而无需重启,从而实现热部署,当然就阿尔萨斯本身是提供 mc 命令,可以直接在内存中编译java文件,但是自己试了几次失败了,所以,需要先在本地编译相关的Java文件,然后再用 redefine命令来实现热部署。

3.本地脚本编写原理

1)执行命令(简化)

mvn clean compile -DskipTests

编译所需要的模块,获取相关class文件

2)找到涉及的class文件,通过

scp -P$remote_port $local_clazz_path $remote_user_name@$remote_host:$remote_path

上传相关的class文件

3)本地通过

ssh -p$remote_port $remote_user_name@$remote_host "sh $path/hot_deploy.sh $remote_clazz_path" “$project_name”

调用远程脚本实现热部署

四、本地脚本如下:

#!/usr/bin/env bash
env_name=$1
git_manual_flag=$2

remote_host=
remote_port=
remote_pass_word=
remote_user_name=
remote_path="/home/work/local/arthas-boot/class"
remote_deploy_path="/home/work/local/arthas-boot/hot_deploy.sh"
all_java_class_path=
skip_maven=

check_parameter(){
    if [ -z "$env_name" ]; then
        echo "please set environment,for example:33[31m  sh hot_deploy.sh t3 git 33[0m"
        exit 1
    fi
}

config_env(){
    case $env_name in
        t1)
        remote_host="11.11.11.11"
        remote_port=22
        remote_pass_word="123456"
        remote_user_name="root"
        ;;
        *)
        echo "env_name error:$env_name"
        exit 1
    esac
}

process_produce_class(){
    modules="$1"
    if  test -z "$skip_maven"; then
        start_time=`date +"%F %T"`
        start=`date +%s`
        echo "maven compile start $start_time"
        maven_modules=$(echo "$modules" | tr "
" "," | sed "s/,$//g")
        mvn clean compile  -Dmaven.test.skip=true -T 8C  -Dmaven.compile.fork=true -pl "$maven_modules" -am
        end_time=`date +"%F %T"`
        stop=`date +%s`
        echo "maven compile end $end_time,total time:$[ stop - start ]s"
    fi
}


scp_class(){
  clazz_path="$1"
  remote_clazz_path="$2"
  sshpass -p "$remote_pass_word" ssh -n  "$remote_user_name"@"$remote_host" -p"$remote_port" "mkdir -p $remote_clazz_path"
  sshpass  -p "$remote_pass_word" scp  -P"$remote_port" "$clazz_path" "$remote_user_name"@"$remote_host":"$remote_clazz_path"
  if [ ! "$?" -eq 0 ];then
       echo "scp class failed clazz_path:$clazz_path"
       return 1
  fi
 return 0
}
change_class(){
       clazz_path="$1"
       remote_clazz_path="$remote_path/$clazz_path"
       project_name="$2"
       if test -z "$remote_clazz_path"; then
           echo "change_class,remote_clazz_path is not exits"
           return
       fi
       if test -z "$project_name"; then
           echo "change_class,project_name is not exits"
           return
       fi
       change_res=$(sshpass -p "$remote_pass_word" ssh -n  "$remote_user_name"@"$remote_host" -p"$remote_port" "sh $remote_deploy_path ${remote_clazz_path} ${project_name}")
       success_count=$(echo "$change_res" | grep -c "success")
       res=
       clazz_name=$(basename "$remote_clazz_path")
       remote_failed_messag=
       if ! test "$success_count" -eq 0; then
            res=$(echo "$change_res" | tail -2 | head -1)
            echo "--------------------------------------------------------------------
arthas result:
clazz_name:$clazz_name
$res
-------------------------------------------------------------------"
            success_clazz_path="${success_clazz_path}$clazz_path
"
       else
            res="$change_res"
            remote_failed_message="
remote_clazz_path:$remote_clazz_path
project_name:$project_name
error message:"
            echo "33[31m--------------------------------------------------------------------
arthas result:
clazz_name:$clazz_name${remote_failed_message}
$res
--------------------------------------------------------------------33[0m"


       fi
}


produce_class(){
    batch_java_path="$1"
    modules=`echo "$batch_java_path" | awk -F "/src" "{print $1}" | sort -nr | uniq`
    if [ -z "$modules" ]
        then
        echo "modules is empty"
        return 1
     fi
   echo "modules:$(echo $modules | tr "
" " ")"
   process_produce_class "$modules"
}

process(){
    batch_java_path="$1"
    batch_clazz_name=`echo "$batch_java_path" | sed "s/src/main/java/target/classes/g" | sed "s/.java/.class/g" | tr "
" " "`
    echo "redefine clazz name:
$batch_clazz_name"
    for clazz in $batch_clazz_name
        do
           if test -f "$clazz"; then
             remote_clzz_dir="$remote_path/$(dirname "$clazz")"
             scp_class "$clazz" "$remote_clzz_dir"
             if test "$?" -eq 0 ; then
                 #project_name 不同的项目截取project_name不一样,这个地方需要使用者自己去截取,适配自己的项目,因为在我现在项目里,是分多模块的,在同一台测试机器里是部署了多个项目,所以为了适配各个项目,需要获取项目名称,也就是project_name
                 project_name=`echo "$clazz" | awk -F "/" "{print $1}"`
                 if [ "$project_name" == "web" ]; then
                       project_name=`echo "$clazz" | awk -F "/" "{print $2}" | awk -F "-" "{print $NF}"`
                 fi
                change_class "$clazz" "$project_name"
             fi
          else
           echo "clazz not exists,clazz:$clazz"
          fi
        done
}

count_success_failed(){
   if test -n "$success_clazz_path"; then
      success_class_path=$(echo "$success_clazz_path"  | sed "s/
//g"| sed "s/target/classes/src/main/java/g" | sed "s/.class/.java/g")
      for class in "$all_java_class_path"
         do
           local count=`echo "$success_class_path" | grep -cw "$class"`
           if test "$count" -eq 0; then
              failed_class_path="$failed_class_path$class
"
           fi
         done
   else
        failed_class_path="$all_java_class_path"
   fi
   success_class_path=$(echo "$success_class_path" | sed "s/
$//g")
   failed_class_path=$(echo "$failed_class_path" | sed "s/
$//g")
   if test -n "$success_class_path"; then
      echo "33[32m********************************************************************
success class:
$success_class_path
********************************************************************33[0m"
   fi
   if test -n "$failed_class_path"; then
      echo "33[34m********************************************************************
failed class:
${failed_class_path}
********************************************************************33[0m"
   fi
}

main_manual(){
   class_names="$1"
   echo "class_names:$class_names"
   local batch_java_path=
   for cn in $class_names
   do
     local class_name="$cn"
     local temp_path=`find . -type f -name "$class_name.java" | sed "s/^.///g"`
     local count=`echo "$temp_path"| grep -c ".java$"`
     local java_path=
     if [ "$count" -eq  0 ]; then
          echo "can not find this class,by name:$class_name"
     elif [ "$count" -gt 1 ]; then

          echo "33[31mfile greater than 1,please choose line number: 33[0m"
          temp_path_line=`echo "$temp_path" | awk "$0=NR"  "$0"`
          echo  "33[31m$temp_path_line 33[0m"
          read num
          java_path=`echo "$temp_path" | sed -n "${num}p"`
          if [ "X$java_path" == "X" ]; then
              echo "line number error,number:$num"
          fi
     else
          java_path="$temp_path"
     fi

     if test -f "$java_path"; then
        batch_java_path="$batch_java_path$java_path
"
     fi
   done
   if test -n "$batch_java_path"; then
        batch_java_path=$(echo "$batch_java_path" | sed "s/
$//g")
        all_java_class_path="$batch_java_path"
        produce_class "$batch_java_path"
        process "$batch_java_path"
   fi
}

main_skip_maven(){
    skip_maven="true"
    main_manual "$1"
}

main_git(){
   local batch_java_path=`git status | grep -o "modified.*.java$" | awk -F "   " "{print $2}"`
    if [ -z "$batch_java_path" ]
     then
        echo "no modify classes by git status"
        exit 1
    fi
    all_java_class_path="$batch_java_path"
    produce_class "$batch_java_path"
    process "$all_java_class_path"
}

main() {
    check_parameter
    config_env
    if test -n "$git_manual_flag"; then
        case "$git_manual_flag" in
              git)
              echo "use git................."
              main_git
              ;;
              skip)
              echo "use skip maven................."
              shift
              shift
              main_skip_maven "$*"
              ;;
              *)
              shift
              echo "use manual.............."
              main_manual "$*"
              ;;
        esac
              count_success_failed
    else
        echo "please use the way of git or input other class"
        exit 1
    fi
}
main "$@"

2.远程脚本
1)远程脚本名称:hot_deploy.sh
2)远程脚本位置:/home/work/local/arthas-boot
3)代码如下:

#!/bin/bash
class_path=$1
project_name=$2
final_port=9998
arthas_path="/home/work/local/arthas-boot"
proc_flag_name=
pid=
get_port(){
    case $project_name in
         project_a )
                 final_port=8881
                 proc_flag_name="org.apache.catalina.startup.Bootstrap"
         ;;
    
         * )
         echo "project_name error:$project_name"
         exit 1
         ;;
    esac
}

check_pid(){
 pid=$(ps -ef | grep ${proc_flag_name} | grep -v "grep" | awk "{print $2}")
 if [ -z $pid ]; then
    echo "pid error, pid:$pid, class_path:$class_path"
 fi
}
load_class(){
    echo "redefine start,class name:$class_path"
    cd $arthas_path
    pwd
    {
     echo redefine $class_path
     sleep 3
     echo exit
    } | "${JAVA_HOME}/bin/java" -jar arthas-boot.jar ${pid} --telnet-port ${final_port}  --http-port -1
}
get_port
check_pid
load_class

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/74987.html

相关文章

  • 多机部署工具 Capistrano 起手式

    摘要:多机热部署同时升级多台服务器什么是是一种在多台服务器上运行脚本的开源工具,它主要用于部署应用。它自动完成多台服务器上新版本的同步更新,包括数据库的改变。 Capistrano 什么是多机热部署 热部署,就是在应用正在运行的时候升级软件,却不需要重新启动应用。多机热部署 ,同时升级多台服务器 什么是Capistrano 是一种在多台服务器上运行脚本的开源工具,它主要用于部署web应用。它...

    vspiders 评论0 收藏0
  • Day 28: OpenShift的Eclipse集成

    摘要:今天的天学习种新技术我決定介绍的集成。会警告该插件未签名。同时将创建一个私有的仓库并克隆到本地。热部署仅仅替换文件而不会停止服务。如果将其禁用,那么应用将使用。转到视图发布改动。删除模板文件以上版本下,为可选。 编者注:我们发现了有趣的系列文章《30天学习30种新技术》,正在翻译,一天一篇更新,年终礼包。下面是第 28 天的内容。 今天的《30天学习30种新技术》 我決定介绍Op...

    U2FsdGVkX1x 评论0 收藏0
  • 【效率专精系列】几种常见的JVM部署技术及实现难点浅谈

    摘要:而热部署技术能够帮助开发人员减少重新部署的等待时间。本文的目的为调研热部署的技术现状及其对开发效率的帮助,并简单梳理其技术实现的难点。热部署技术总结热部署目前有多种技术实现官方开源商业。 开发、自测、联调期间代码可能会被频繁地修改,通常即使只增加了一行代码,都需要重启容器以检查执行效果。而热部署技术能够帮助开发人员减少重新部署的等待时间。本文的目的为调研热部署的技术现状及其对开发效率的...

    dongfangyiyu 评论0 收藏0
  • 慕课网_《Spring Boot部署》学习总结

    时间:2017年12月01日星期五说明:本文部分内容均来自慕课网。@慕课网:http://www.imooc.com 教学源码:无 学习源码:https://github.com/zccodere/s... 第一章:课程介绍 1-1 课程介绍 热部署的使用场景 本地调式 线上发布 热部署的使用优点 无论本地还是线上,都适用 无需重启服务器:提高开发、调式效率、提升发布、运维效率、降低运维成本 前置...

    Channe 评论0 收藏0
  • 使用web/phpstorm将本地代码实时自动同步到远程服务器

    摘要:设置同步但是这时候要实现同步还是要手动传输的,距离实现自动化还差一点点,打开,我们把一项改为,意思也就是每次保存都会同步到远程服务器。参考使用将本地代码实时自动同步到远程服务器 场景   如果开发和测试环境不同,或者经常使用机器是windows,项目要求必须liunx,这时候我选择虚拟机安装liunx,部署ssh服务,主机安装winscp配合putty,使用webstorm开发,对于w...

    Julylovin 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<