Java 工程在生产环境运行时,一般需要构建成一个jar,同时在运行时需要把依赖的jar添加到classpath中去,如果直接运行添加classpath很不方便,比较方便的是创建一个shell脚本。在公司项目中看到把工程代码和依赖jar包合并到一块,省去设置classpath的麻烦。但这样把项目jar依赖绑定死,被其它项目引入,容易造成jar依赖冲突,如果用maven管理java项目,导致提交到公司仓库jar过于庞大,同时也失去maven对jar依赖管理的作用。
为了方便java项目部署运行,这里为构建部署包定义一个固定格式:
/java 项目
/lib --存放所有依赖jar
/conf --存放配置文件,例如:log4j, spring, properties等配置文件,不放入jar是为
了方便修改这些配置文件
/logs --运行时自动创建的目录,存放日志文件
/bin --存放运行脚本: server.sh 启动和停止项目运行。
如果在构建部署包时,需要我们手动去创建这样的目录,把文件拷贝相应目录,实在是太繁琐了,幸好maven为我们这样“懒惰”coder提供了一个很好的plugin:maven-assembly-plugin,可以去定制这样的部署结构
1:配置maven-assembly-plugin
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-assembly-plugin</artifactId> <configuration> <descriptors> <descriptor>src/main/assembly/assembly.xml</descriptor> </descriptors> </configuration> <executions> <execution> <id>make-assembly</id> <phase>package</phase> <goals> <goal>single</goal> </goals> </execution> </executions> </plugin>
2:assembly 配置打包格式
定义在assembly.xml文件中,文件中配置信息不作过多解释,可以参考相应文档
<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd"> <id>bin</id> <formats> <format>tar.gz</format> </formats> <dependencySets> <dependencySet> <useProjectArtifact>true</useProjectArtifact> <outputDirectory>lib</outputDirectory> <scope>runtime</scope> </dependencySet> </dependencySets> <fileSets> <fileSet> <outputDirectory>/</outputDirectory> <includes> <include>README.txt</include> </includes> </fileSet> <fileSet> <directory>src/main/scripts</directory> <outputDirectory>/bin</outputDirectory> <lineEnding>unix</lineEnding> <fileMode>0755</fileMode> <includes> <include>*.sh</include> </includes> </fileSet> <fileSet> <directory>target/classes</directory> <outputDirectory>/conf</outputDirectory> <includes> <include>*.xml</include> </includes> </fileSet> </fileSets> </assembly>
下面这段配置主要从src/main/scripts目录获取shell脚本复制到bin目录。同时设置文件模式为unix,文件具有可执行权限。
<directory>src/main/scripts</directory> <outputDirectory>/bin</outputDirectory> <lineEnding>unix</lineEnding> <fileMode>0755</fileMode> <includes> <include>*.sh</include> </includes>
3:启动类设计
在学习metamorphosis的时候,对它的启动脚本做了一些了解,发现服务stop方式设计比较优雅,通过JMX连接JVM,去关闭系统内部资源,再kill掉进程。
UeapServerMBean定义stop方法,实现类UeapServer完成系统启动加载和停止功能。ServerStartup是main方法入口,调用 UeapServer启动方式,并注册 UeapServer到JMX中。
4:启动脚本
系统启动脚本分为了两个文件:
env.sh 配置一些环境变量和JVM参数,实际应用中只需要修改 SERVER_NAME、 STARTUP_CLASS和 UEAP_JVM_ARGS变量名称。
server.sh 实际运行脚本,提供启动、停止、运行状态查询、重启功能,实际应用中不需要改动该文件。
env.sh
#!/bin/bash #Config your java home #JAVA_HOME=/opt/jdk/ if [ -z "$JAVA_HOME" ]; then export JAVA=`which java` else export JAVA="$JAVA_HOME/bin/java" fi UEAP_HOME=$BASE_DIR SERVER_NAME="collect master" STARTUP_CLASS="com.starit.ueap.collect.master.ServerStartup" #Ueap JMX port export JMX_PORT=9123 export CLASSPATH=$BASE_DIR/conf:$(ls $BASE_DIR/lib/*.jar | tr '\n' :) #UEAP jvm args UEAP_JVM_ARGS="-Xmx512m -Xms256m -server" UEAP_JVM_ARGS="$UEAP_JVM_ARGS -cp $CLASSPATH -Dueap.home=$ueap_home -Dcollect.start.worker=false" if [ -z "$UEAP_ARGS" ]; then export UEAP_ARGS="$UEAP_JVM_ARGS" fi
server.sh
#!/bin/bash if [ -z "$BASE_DIR" ] ; then PRG="$0" # need this for relative symlinks while [ -h "$PRG" ] ; do ls=`ls -ld "$PRG"` link=`expr "$ls" : '.*-> \(.*\)$'` if expr "$link" : '/.*' > /dev/null; then PRG="$link" else PRG="`dirname "$PRG"`/$link" fi done BASE_DIR=`dirname "$PRG"`/.. # make it fully qualified BASE_DIR=`cd "$BASE_DIR" && pwd` #echo "collect master is at $BASE_DIR" fi source $BASE_DIR/bin/env.sh AS_USER=`whoami` LOG_DIR="$BASE_DIR/logs" LOG_FILE="$LOG_DIR/server.log" PID_DIR="$BASE_DIR/logs" PID_FILE="$PID_DIR/.run.pid" function running(){ if [ -f "$PID_FILE" ]; then pid=$(cat "$PID_FILE") process=`ps aux | grep " $pid " | grep -v grep`; if [ "$process" == "" ]; then return 1; else return 0; fi else return 1 fi } function start_server() { if running; then echo "$SERVER_NAME is running." exit 1 fi mkdir -p $PID_DIR touch $LOG_FILE mkdir -p $LOG_DIR chown -R $AS_USER $PID_DIR chown -R $AS_USER $LOG_DIR echo "$JAVA $UEAP_JVM_ARGS -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false \ -Dcom.sun.management.jmxremote.port=$JMX_PORT $STARTUP_CLASS" sleep 1 nohup $JAVA $UEAP_JVM_ARGS -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false \ -Dcom.sun.management.jmxremote.port=$JMX_PORT $STARTUP_CLASS 2>&1 >>$LOG_FILE & echo $! > $PID_FILE chmod 755 $PID_FILE sleep 1; tail -F $LOG_FILE } function stop_server() { if ! running; then echo "$SERVER_NAME is not running." exit 1 fi count=0 pid=$(cat $PID_FILE) while running; do let count=$count+1 echo "Stopping $SERVER_NAME $count times" if [ $count -gt 5 ]; then echo "kill -9 $pid" kill -9 $pid else $JAVA $TOOLS_ARGS com.starit.ueap.common.shell.StopServerTool -host 127.0.0.1 -port $JMX_PORT $@ kill $pid fi sleep 3; done echo "Stop $SERVER_NAME successfully." rm $PID_FILE } function status(){ if running; then echo "$SERVER_NAME is running." else echo "$SERVER_NAME was stopped." fi } function help() { echo "Usage: server.sh {start|status|stop|restart|reload}" >&2 echo " start: start the $SERVER_NAME server" echo " stop: stop the $SERVER_NAME server" echo " restart: restart the $SERVER_NAME server" echo " status: get $SERVER_NAME current status,running or stopped." } command=$1 shift 1 case $command in start) start_server $@; ;; stop) stop_server $@; ;; status) status $@; ;; restart) $0 stop $@ $0 start $@ ;; help) help; ;; *) help; exit 1; ;; esac
4:执行mvn install或者mvn package 可以再target生成tar.gz后缀文件。提交到linux系统,解压缩即可运行。(不考虑window环境)