springboot项⽬实现jar包外配置⽂件管理
背景
为实现快速搭建和开发,项⽬以Springboot框架搭建,springboot搭建的项⽬可以将项⽬直接打成jar包并运⾏,⽆需⾃⼰安装配置Tomcat或者其他服务器,是⼀种⽅便快捷的部署⽅式。
假设项⽬以最常规的⽅式打包成⼀个整体的jar包部署,即配置⽂件和第三⽅依赖包都包含在jar包⾥,就会有如下两个问题
问题⼀:项⽬运⾏过程中,要改动配置⽂件的话需要重新打包并部署。
问题⼆:多个第三⽅依赖包都相近的项⽬要部署在同⼀台服务器时,各⾃的jar包都包含了相同的第三⽅依赖包(假设项⽬jar包有100M,第三⽅依赖包可能就占⽤了99M),这样第三⽅依赖包冗余造成了服务器资源的浪费以及降低了项⽬部署的效率。
如果将各项⽬的配置⽂件、第三⽅依赖包都提取到jar包外统⼀管理,这样即提升了项⽬打包效率⼜节约了服务器的磁盘消耗,同时项⽬的运维也是⾮常⽅便的,改动了配置⽂件重启下服务就可以了,⽆需重新构建部署。
下⾯是具体的实现⽅案
1. 配置⽂件统⼀管理
1.1 springboot核⼼配置⽂件
Springboot读取核⼼配置⽂件(application.properties)的优先级为
Jar包同级⽬录的config⽬录
Jar包同级⽬录
classPath(即resources⽬录)的config⽬录
classpath⽬录
上⾯是springboot默认去拿⾃⼰的核⼼配置⽂件的优先级,还有⼀种最⾼优先级的⽅式是项⽬启动时通过命令的⽅式指定项⽬加载核⼼配置⽂件,命令如下
java –jar -fig.location=xxx/xxx/xxxx.properties xxxx.jar
如果Spring Boot在优先级更⾼的位置到了配置,那么它会⽆视优先级更低的配置
1.2 其他资源配置⽂件
上⾯描述的Springboot核⼼⽂件已经能够提取出jar包外进⾏管理了,但是还有其他⼀些业务上的配置⽂件,如数据源配置⽂件,公共资源定义配置⽂件(常量,FTP信息等),quartz定时器,⽇志等配置⽂件我们如何去提取出来并确保能在代码中引⽤到呢
我们知道Springboot项⽬可以通过注解⽅式来获取相关配置⽂件,所以我们也是通过注解⽅式让项⽬能够引⽤到jar包外部的配置⽂件的,如下图:
@PropertySource⾥⾯的value有两个值,第⼀个是classpath下config⽬录下的数据源配置⽂件,第⼆个则是根
据spring.profiles.path动态获取的⽬录,spring.profiles.path是我们在核⼼⽂件⾃定义的⼀个配置项,它的值是我们配置⽂件统⼀管理的⽂件夹路径,后⾯的ignoreResourceNotFound=true则是设定假如根据前⾯⼀个路径没有到相关配置⽂件,则根据第⼆个路径去。
我们还可以直接根据路径,⽤FileSystemResource类去加载⼀个配置⽂件实例出来,如下图
原理类似,根据在核⼼⽂件⾃定义的统⼀配置⽬录的路径来加载配置⽂件
另外logback⽇志配置⽂件加载⽅式如下:
综上所述,我们梳理⼀下实现⽅案的思路
1、        在springboot核⼼⽂件⾥定义⼀个spring.profiles.path配置项,它的值指向我们所有配置⽂件统⼀放置的⽬录,包含核⼼⽂件⾃⾝也是放置在⾥⾯的
2、        代码或者配置⽂件⾥加载配置⽂件的地⽅也应该获取spring.profiles.path配置项来动态加载该路径下的配置⽂件
3、        l⽂件修改打包相关模块,将配置⽂件排除,这样我们打出的jar包是不含配置⽂件的,打包配置请参考⽂档节点3
4、        启动jar包时,通过命令指定加载的核⼼⽂件为spring.profiles.path下的核⼼⽂件
2. 第三⽅依赖包统⼀管理
通常第三⽅jar包可以打进jar包⾥,也可以放在项⽬jar包同级⽬录下的lib⽬录,我们可以根据修改l打包配置来实现,请参考⽂档节点3打包配置
3. 打包配置
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>true</filtering>
</resource>
<resource>
<directory>src/main/resources</directory>
<!—打包时排除配置⽂件-->
<excludes>
<exclude>**/*.properties</exclude>
<exclude>**/*.xml</exclude>
<exclude>**/*.yml</exclude>
</excludes>
</excludes>
<filtering>false</filtering>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
<fork>true</fork>
<skip>true</skip>
<executable>
C:/Program Files/Java/jdk1.8.0_161/
</executable>
</configuration>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<classpathPrefix>lib/</classpathPrefix>
<useUniqueVersions>false</useUniqueVersions>
<mainClass&q.demo.Application</mainClass>
</manifest>
<manifestEntries>
<Class-Path>./</Class-Path>
</manifestEntries>
</archive>
<excludes>
<exclude>*.properties</exclude>
<exclude>*.yml</exclude>
<exclude>*.xml</exclude>
<exclude>config/**</exclude>
</excludes>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>copy</id>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>
${project.build.directory}/lib
</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
改好l的build模块后,就可以通过mvn package 或者mvn install打出我们的jar包了
4. 项⽬管理shell脚本编写
⾃定义shell脚本,实现项⽬的启动,停⽌,状态,重启操作:
#!/bin/bash
#这⾥可替换为你⾃⼰的执⾏程序,其他代码⽆需更改
APP_NAME=demo1-0.0.1-SNAPSHOT.jar
JVM="-server -Xms512m -Xmx512m -XX:PermSize=64M -XX:MaxNewSize=128m -XX:MaxPermSize=128m -Djava.awt.headless=true -XX:+CMSClassUnloadingE APPFILE_PATH="-fig.location=/usr/local/demo/config/application-demo1.properties"
#使⽤说明,⽤来提⽰输⼊参数
usage() {
echo "Usage: sh 执⾏脚本.sh [start|stop|restart|status]"
exit 1
}
#检查程序是否在运⾏
is_exist(){
pid=`ps -ef|grep $APP_NAME|grep -v grep|awk '{print $2}' `
#如果不存在返回1,存在返回0
if [ -z "${pid}" ]; then
return 1
springboot架构图
else
return 0
fi
}
#启动⽅法
start(){
is_exist
if [ $? -eq "0" ]; then
echo "${APP_NAME} is already running. pid=${pid} ."
else
nohup java $JVM -jar $APPFILE_PATH $APP_NAME > /dev/null 2>&1
fi
}
#停⽌⽅法
stop(){
is_exist
if [ $? -eq "0" ]; then
kill -9 $pid
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
status
;;
"restart")
restart
;;
*)
usage
;;
esac
5. 部署
linux服务器上新建个⽂件夹,将我们打好的项⽬jar包都丢进去,在jar包的同级⽬录新建config和lib⽂件夹,分别将配置⽂件和第三⽅依赖包丢进去,其结构如下图,*.sh为⾃⼰写的项⽬启动shell脚本
打开config内的springboot核⼼⽂件(如application-demo1.properties⽂件),
spring.profiles.path配置项改成当前配置⽂件所在的⽬录,假设为/usr/local/demo/config
打开*.sh脚本,修改APPFILE_PATH的值,如下
APPFILE_PATH="-fig.location=/usr/local/demo/config/application-demo1.properties"
6. 项⽬管理
进⼊jar包所在⽬录执⾏下⾯命令
sh demo1.sh start 启动项⽬
sh demo1.sh stop 停⽌项⽬
sh demo1.sh restart重启项⽬
sh demo1.sh status项⽬状态