Linux环境下Java应用部署详解

1.命令行启动Java程序

首先从最基础的Java程序执行讲起,想要在Linux中执行Java程序,假定已安装JDK且配置好了Java的环境变量,那么手动执行程序有两种方式:

  • 如果是简单的Main-Class启动
java -classpath C:\java\DemoClasses HelloWorld
  • 如果是Jar包程序启动
java -jar HelloWorld.jar

注意:当class或jar不在运行目录下,可以使用-classpath 参数指定文件所在目录。

2.后台不断运行Java程序

通过方法1执行的Java程序,会在会话关闭后或者ctrl+c操作后停止运行,因此需要用Linux中nohup & 结合方式,不挂断的永久在后台运行程序。

nohup java -jar demo.jar &

在以上命令中,我们还可以做一点小优化处理:

nohup java -jar demo.jar >./start.log 2>&1 &
  • 使用2>&1表示 错误和输出都传到nohup.out文件中,默认状态只把输出输出到nohup.out文件中
  • nohup命令默认输出到nohup.out文件中,重定向输出到start.log。

3.部署Shell脚本

企业在搭建线上环境的DevOps体系中,从开发到线上部署可以粗略分为四个步骤,1、开发提交代码,2、MAVEN编译打包,3、通过Jekins等工具将jar包部署到测试环境。4、测试验证通过、运营验收后,部署到生产环境,当然有些还会发布灰度环境,这是更细粒度的环节。

在部署测试和生产时,如果通过脚本启动Java程序通常需要三个方面的信息:

  • 启动时指定JVM参数,一般为-*命名
  • 启动时指定外部配置路径和系统参数,一般以-D*命名
  • 启动时指定项目特有的配置参数,激活环境等等,一般为--

(1).JVM参数指定

首先指定JVM参数,列表如下:

-Xmx512m 最大总堆内存,一般设置为物理内存的1/4
-Xms512m 初始总堆内存,一般将它设置的和最大堆内存一样大,这样就不需要根据当前堆使用情况而调整堆的大小了
-Xmn192m 年轻带堆内存,sun官方推荐为整个堆的3/8
堆内存的组成 总堆内存 = 年轻带堆内存 + 年老带堆内存 + 持久带堆内存
年轻带堆内存 对象刚创建出来时放在这里
年老带堆内存 对象在被真正会回收之前会先放在这里
持久带堆内存 class文件,元数据等放在这里
-XX:PermSize=128m 持久带堆的初始大小
-XX:MaxPermSize=128m 持久带堆的最大大小,eclipse默认为256m。如果要编译jdk这种,这个可以设大点,因为它的类太多了。

(2).外部配置路径

如果是SpringBoot项目往往需要将properties或yaml文件放到jar包之外的目录,单独指定一个独特的外部配置目录,存放配置文件,因为生产环境的数据库帐号密码等配置查看只有Ops有权限,Dev无权限。此时,该外部配置路径需要放到类路径环境中,程序才能访问得到,加载外部目录到CLASSPATH中可以有如下几种方式:

  • 配置全局配置环境路径-Dglobal.config.path
java -Dglobal.config.path=/wls/appsystem/  -jar basic.jar 
  • -Xbootclasspath会完全取代基本核心的Java class搜索路径,不推荐用
java -Xbootclasspath/a:/wls/appsystem/ -jar basic.jar
  • 配置类路径的环境变量,在原来的基础上附加。
export CLASSPATH=$CLASSPATH:/wls/appsystem/

这里推荐第一种的实现方式,类路径也会显式的输出在进程信息当中。Java启动的自定义系统配置参数,命名一般是-D开头,且顺序是要放在JVM系统参数之后,在-jar之前!

(3).系统或项目配置

还有一些系统和项目配置的参数也可以直接写在启动参数里:

  • 如指定使用的环境配置文件
java -jar basic.jar --spring.profiles.active=stg
  • 如指定启动的端口信息
java -jar basic.jar --server.port=8000

有些不方便写在配置文件中的配置项也可以放到此处,这样的场景也比较普通,比如搭建集群服务,需要获取本机IP作为注册zk注册中心的IP,这样的配置就不能写在代码配置里,只能放在每个机器的启动参数中。

(4).Shell脚本部署

将前面三项提到的启动参数写入到部署脚本,就可以通过指令来实现Java应用的启停,这些都是围绕进程的生命周期来写的,最核心的方法是在start方法中。

APP_NAME=basic.jar
JVM_SETTINGS="-Xms128m -Xmx128m -Dglobal.config.path=/wls/appsystem"
JAVA_OPS="--spring.profiles.active=stg"

# show usage
usage() {
    echo "Usage: sh start.sh [start|stop|restart|status]"
    exit 1
}

# check app status
is_exist() { 
    pid=`ps -ef | grep $APP_NAME | grep -v grep | awk '{print $2}' `
    # return 1 if exist, else 0
    if [ -z "${pid}" ]; then
      return 1
    else
      return 0
    fi
}

start() {
   is_exist
   if [ $? -eq "0" ]; then
     echo "${APP_NAME} is already running. pid=${pid} ."
   else
     echo "begin to start application..."
     nohup java $JVM_SETTINGS -jar $APP_NAME $JAVA_OPS  >./start.log 2>&1 &
     #echo "start application success!"
     tail -f start.log
   fi
}

stop() {
   is_exist
   if [ $? -eq "0" ]; then
     kill -9 $pid
     echo "application stop sucess!"
   else
     echo "${APP_NAME} is not running"
   fi
}

status() {
   is_exist
   if [ $? -eq "0" ]; then
     echo "${APP_NAME} is running. Pid is ${pid}"
   else
     echo "${APP_NAME} is not running."
   fi
}

restart() {
   stop
   start
}

case "$1" in
   "start")
     start
     ;;
   "stop")
     stop
     ;;
   "status")
     status
     ;;
   "restart")
     restart
     ;;
   *)
     usage
     ;;
esac

推荐阅读更多精彩内容

  • ORA-00001: 违反唯一约束条件 (.) 错误说明:当在唯一索引所对应的列上键入重复值时,会触发此异常。 O...
    我想起个好名字阅读 1,691评论 0 6
  • Swift1> Swift和OC的区别1.1> Swift没有地址/指针的概念1.2> 泛型1.3> 类型严谨 对...
    cosWriter阅读 4,208评论 1 15
  • 一:java概述:1,JDK:Java Development Kit,java的开发和运行环境,java的开发工...
    ZaneInTheSun阅读 956评论 0 5
  • 一、基础知识:1、JVM、JRE和JDK的区别:JVM(Java Virtual Machine):java虚拟机...
    杀小贼阅读 529评论 0 2
  • 一. Java基础部分.................................................
    wy_sure阅读 1,570评论 0 7