万能的 DSL 项目模板(Java)
# 前言
Jpom 在之前很长的一段时间都只支持管理 Java 项目并且管理的项目方式也比较简单粗暴,不能管理一些多目录结构等复杂的项目。
自从 Jpom 2.8.6
版本上线 DSL 模式
项目后,经过大家的使用反馈在 2.8.6 ~ 2.9.18
20+个版本迭代后,现在 Jpom 可以很灵活的实现自定义项目管理
温馨提醒
如果您现在已经安装 Jpom 并且使用的非 2.9.18 版本,建议先更新到 2.9.18 版本后再使用,最新版本优化和修改了 DSL 相关功能
本文主要使用一个典型的 Java 多目录层级项目、并且自定义启动、停止、查询状态、重启流程脚本来讲解,并且本文也会提到在 Jpom 中如何查看自定义项目的日志
如果您还不了解 Jpom 中的 DSL 模式是什么可以查看文档:DSL 介绍>>
注意:本文采用一键安装同时基于 2.9.18 版本讲解,系统为 centos
# 需要准备的环境
- Jpom 服务端(已经安装好、并且配置好了 maven 环境)
- Jpom 插件端(已经安装好)
- 一个 Java 项目仓库 并且已经有管理脚本
本文就不再从零开始讲解安装教程,如果有不知道该如何安装的可以查看相关文档
本文使用物理机直接安装 Jpom 服务端的方式
本文使用的项目案例是一个 SpringBoot 项目
- 项目采用胖 jar 的方式运行(您可以根据自己需求修改为
classpath
模式) - 项目使用
maven-assembly-plugin
插件打包 - 项目采用外置:
application.yml
、logback.xml
配置文件 - 使用
G1GC
垃圾回收机制(具体请参考 ./bin/command.sh (opens new window) )
案例仓库地址:https://gitee.com/keepbx/Jpom-demo-case/ (opens new window) -> springboot-test-jar2 (opens new window)
项目相关的配置文件会附到文章末尾,可以自取(copy)、或者进入仓库查看完整代码
项目目录结构如下:
.
├── conf => 配置文件目录
├──── application.yml => springboot 核心配置文件
├──── logback.xml => logback 日志配置文件
├── bin => 项目管理命令目录
├──── command.sh => 目管理命令文件
├── logs => 项目日志目录
├──── stdout.log => 项目控制台日志文件
├──── application.log => 项目 logback 日志文件
├── lib => 项目运行 jar 目录
└──── xxxxx.jar => 项目运行 胖 jar 文件
2
3
4
5
6
7
8
9
10
11
12
# 使用指南
本文默认您已经安装 Jpom、并且已经配置好节点信息了。还不会的请参考其他相关文档
# 创建项目
温馨提醒
这时在项目列表中运行状态出现感叹号,不要慌忽略即可。因为现在项目文件夹还是空的没有办法正常执行脚本
DSL 配置内容
# scriptId 可以是项目路径下脚本文件名或者系统中的脚本模版ID
description: 测试
run:
start:
scriptId: ./bin/command.sh
scriptArgs: start exit --spring.profiles.active=test
scriptEnv:
"USR_JVM_SIZE": -Xms256m -Xmx1024m
status:
scriptId: ./bin/command.sh
scriptArgs: status
stop:
scriptId: ./bin/command.sh
scriptArgs: stop
restart:
scriptId: ./bin/command.sh
scriptArgs: restart exit --spring.profiles.active=test
scriptEnv:
"USR_JVM_SIZE": -Xms256m -Xmx1024m
file:
# 备份文件保留个数
# backupCount: 5
# 限制备份指定文件后缀(支持正则)
# backupSuffix: [ '.jar','.html','^.+\.(?i)(txt)$' ]
config:
# 是否开启日志备份功能
# autoBackToFile: true
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# 配置构建
这里我们主要是演示和介绍使用 Jpom 在线构建来发布项目
本文自动忽略配置仓库环节,直接上手配置构建(不会配置仓库的也请查阅相关文档即可),并且文使用在本地构建来执行(需要提前配置 maven 环境,不会也请查阅相关文档即可)
- 执行构建
# 管理项目
回到项目列表中,查看项目状态已经是运行中了
- 项目控制台管理
在项目控制台中我们可以查看到在执行项目脚本中产生的日志信息,这样可以方便我们定位项目执行过程中的信息
完美实现
到这里我们已经把已经自定义项目部署在 Jpom 中了,并且可以在线查看项目状态,启动、停止、重启等操作,而且搭配上项目监控还可以实时掌握项目宕机情况
相关文档:
# 如何管理项目日志
目前已经将项目部署到 Jpom 中啦,并且可以很方便管理项目,但是不知道该如何管理项目日志呢?
不要慌、Jpom 目前提供了两种方式来管理项目日志
- 实时阅读
- 日志阅读(搜索)
# 实时阅读
Jpom 里面为项目文件中的文本文件提供了实时阅读功能,这样方便您在 Jpom 中实时查看您项目运行的日志信息
默认并未开启文件阅读功能,需要配置文本文件白名单
这里建议配置一些常用的文本文件后缀即可,比如:log
、sh
、html
、yml
等
配置好后到项目文件夹找到你需要查阅的文件在文件名栏右键
这样您就可以实时查看这个文件的信息了。
# 日志阅读(搜索)
Jpom 里面为项目文件中的文本文件阅读搜索
作用主要是用于日志文件较大时想查找指定关键词相关的日志信息
# DSL 脚本说明
- 脚本里面至少需要实现的三件事:启动、停止、查状态,可选实现重启事件(默认重启流程是调用 stop 再调用 start)
- 查状态输出最后一行需要是
running:$pid
$pid 必须为数字且表示当前项目的进程 id ,如果不匹配项目则显示未运行
提供的示例里面将使用四个函数来实现:start、stop、status、restart
再实际使用中可以随意发挥,不限于只是用来管理 Java 项目,您可以根据你业务需求还实现很多种效果,里面的细节这里不过多的说明,可以自由发挥(给您足够的空间)
脚本里面支持的变量有:${PROJECT_ID}
、${PROJECT_NAME}
、${PROJECT_PATH}
如果多个项目管理方式相同,推荐提前将脚本添加到脚本模版里面,这样可以多个项目重复使用奥(并非一个项目对应一个脚本模版)
# 附件
# 项目 pom.xml 内容
pom.xml 中依赖相关可以直接忽略,参考 build>plugins 相关即可
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>cn.keepbx</groupId>
<artifactId>springboot-test-jar2</artifactId>
<version>0.0.1-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.1</version>
</parent>
<packaging>jar</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<spring-boot.version>2.7.1</spring-boot.version>
<start-class>cn.keepbx.SpringBootApp</start-class>
</properties>
<dependencies>
<dependency>
<groupId>cn.jiangzeyin.fast-boot</groupId>
<artifactId>common-boot</artifactId>
<version>[2.3.0,2.3.99]</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<encoding>${project.build.sourceEncoding}</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.3.0</version>
<configuration>
<archive>
<addMavenDescriptor>true</addMavenDescriptor>
<manifest>
<mainClass>${start-class}</mainClass>
<!-- 是否指定项目classpath下的依赖 -->
<addClasspath>true</addClasspath>
<!-- 指定依赖的时候声明前缀 -->
<classpathPrefix>./</classpathPrefix>
</manifest>
</archive>
<excludes>
<exclude>**/logback**.xml</exclude>
<exclude>**/application**.yml</exclude>
</excludes>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<fork>true</fork>
<mainClass>${start-class}</mainClass>
<jvmArguments>-Dfile.encoding=UTF-8</jvmArguments>
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.4.2</version>
<configuration>
<encoding>${project.build.sourceEncoding}</encoding>
<descriptors>
<descriptor>${basedir}/src/main/assembly/release.xml</descriptor>
</descriptors>
<!-- 如果一个应用的包含多个deploy模块,如果使用同样的包名, 如果把它们复制的一个目录中可能会失败,所以包名加了 artifactId以示区分 -->
<finalName>${project.artifactId}-${project.version}</finalName>
<!-- scm 要求 release 模式打出的包放到顶级目录下的target子目录中 -->
<outputDirectory>target</outputDirectory>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
# assembly/release.xml 内容
<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd">
<id>release</id>
<formats>
<format>dir</format>
<format>tar.gz</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<fileSets>
<fileSet>
<directory>./src/main/bin</directory>
<outputDirectory>bin</outputDirectory>
<includes>
<include>**/*</include>
</includes>
<fileMode>0755</fileMode>
</fileSet>
</fileSets>
<files>
<file>
<source>./src/main/resources/logback-release.xml</source>
<outputDirectory>/conf</outputDirectory>
<destName>logback.xml</destName>
</file>
<file>
<source>./src/main/resources/application.yml</source>
<outputDirectory>/conf</outputDirectory>
<destName>application.yml</destName>
</file>
</files>
<dependencySets>
<dependencySet>
<outputDirectory>lib</outputDirectory>
<includes>
<include>cn.keepbx:springboot-test-jar2</include>
</includes>
</dependencySet>
</dependencySets>
</assembly>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# command.sh 内容
# description: Auto-starts boot
case "$(uname)" in
Linux)
bin_abs_path=$(readlink -f $(dirname $0))
;;
*)
bin_abs_path=$(
cd $(dirname $0)
pwd
)
;;
esac
cygwin=false
linux=false
case "$(uname)" in
CYGWIN*)
cygwin=true
;;
Linux*)
linux=true
;;
esac
base=${bin_abs_path}/..
conf_path="${base}/conf"
Lib="${base}/lib/"
LogPath="${base}/logs/"
Log="${LogPath}/stdout.log"
logback_configurationFile="${conf_path}/logback.xml"
application_conf="${conf_path}/application.yml"
PID_TAG="test-jar-application-${PROJECT_ID}"
AllLog="${LogPath}/application.log"
#-Xms1g -Xmx2g
if [[ -z "${USR_JVM_SIZE}" ]]; then
USR_JVM_SIZE="-Xms256m -Xmx1024m"
fi
JVM_ARGS="-server ${USR_JVM_SIZE} -XX:+UseG1GC -Dfile.encoding=UTF-8"
JVM_ARGS="${JVM_ARGS} -XX:MaxGCPauseMillis=250 -XX:+UseGCOverheadLimit -XX:+ExplicitGCInvokesConcurrent -Djava.awt.headless=true -Djava.net.preferIPv4Stack=true"
JVM_ARGS="${JVM_ARGS} -Xss256k -XX:+AggressiveOpts -XX:-UseBiasedLocking -XX:-OmitStackTraceInFastThrow -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=$LogPath"
JVM_ARGS="${JVM_ARGS} -XX:+UseFastAccessorMethods -XX:+PrintAdaptiveSizePolicy -XX:+PrintTenuringDistribution"
JVM_ARGS="${JVM_ARGS} -Dlogging.config=$logback_configurationFile -Dspring.config.location=$application_conf"
MAIN_ARGS="$*"
WAIT_LOG="$2"
RUN_JAR="${RUN_JAR}"
function checkConfig() {
if [ ! -d "$LogPath" ]; then
mkdir -p "$LogPath"
fi
if [[ ! -f "$logback_configurationFile" ]] || [[ ! -f "$application_conf" ]]; then
echo "Cannot find $application_conf or $logback_configurationFile"
exit 1
fi
if [[ -z "${RUN_JAR}" ]]; then
RUN_JAR=$(ls -t "${Lib}" | grep '.jar$' | head -1)
# error
if [[ -z "${RUN_JAR}" ]]; then
echo "Jar not found"
exit 2
fi
echo "automatic running:${RUN_JAR}"
fi
}
function getPid() {
if $cygwin; then
JAVA_CMD="$JAVA_HOME\bin\java"
JAVA_CMD=$(cygpath --path --unix $JAVA_CMD)
JAVA_PID=$(ps | grep $JAVA_CMD | awk '{print $1}')
else
if $linux; then
JAVA_PID=$(ps -C java -f --width 1000 | grep "$PID_TAG" | grep -v grep | awk '{print $2}')
else
JAVA_PID=$(ps aux | grep "$PID_TAG" | grep -v grep | awk '{print $2}')
fi
fi
echo $JAVA_PID
}
# See how we were called.
function start() {
echo $PID_TAG
checkConfig
if [ ! -f $Log ]; then
touch $Log
fi
# check running
pid=$(getPid)
#echo "$pid"
if [ "$pid" != "" ]; then
echo "Running, please do not run repeatedly:$pid"
exit 1
fi
# start
nohup java -Dappliction=${PID_TAG} ${JVM_ARGS} -jar ${Lib}${RUN_JAR} ${MAIN_ARGS} >$Log 2>&1 &
if [[ ${WAIT_LOG} == "tail" ]]; then
sleep 2s
tail -f $AllLog
fi
echo "auto exit 0"
sleep 1s
exit 0
}
function stop() {
pid=$(getPid)
if [ "$pid" != "" ]; then
echo -n "boot ( pid $pid) is running"
echo
echo -n $"Shutting down boot: "
kill $pid
LOOPS=0
while (true); do
pid=$(getPid)
if [ "$pid" == "" ]; then
echo "Stop and end, in $LOOPS seconds"
break
fi
let LOOPS=LOOPS+1
sleep 1
done
else
echo "boot is stopped"
fi
}
function status() {
pid=$(getPid)
#echo "$pid"
if [ "$pid" != "" ]; then
echo "running:$pid"
else
echo "boot is stopped"
fi
}
function usage() {
echo "Usage: $0 {start|stop|restart|status}"
RETVAL="2"
}
# See how we were called.
RETVAL="0"
case "$1" in
start)
start
;;
stop)
stop
;;
restart)
stop
start
;;
status)
status
;;
*)
usage
;;
esac
exit $RETVAL
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
脚本的几种用法如下:
- 后台启动项目:
bash ./command.sh start
- 查看项目状态:
bash ./command.sh status
- 停止项目:
bash ./command.sh stop
- 后台重启项目:
bash ./command.sh restart
- 启动项目并查看日志:
bash ./command.sh start tail
- 重启项目并查看日志:
bash ./command.sh restart tail
- 后台启动项目并传入参数:
bash ./command.sh start --spring.profiles.active=pro --server.port=8080
- 后台重启项目并传入参数:
bash ./command.sh restart --spring.profiles.active=pro --server.port=8080