文章目录
一、前言
后面我们打算探索SpringBoot下的微服务实践,常常需要部署多个服务。
当前暂时不想讲Jenkins+rencher,打算使用jar包部署。
但SpringBoot默认的打包,把资源包和config包打到了一个jar包,如何让不同服务有不同的配置就成了一个问题。
故本章主要介绍在SpringBoot下,如何使把Config和Resource文件夹从jar包分离出去。
由于本章代码没有太多好讲的,后面基本就贴代码了
二、SpringBoot工程展示
2.1 工程目录
2.2 代码
PackageTestApplication
package indi.zhifa.recipe.test;
@SpringBootApplication(
scanBasePackages = {"indi.zhifa.recipe.test"}
)
public class PackageTestApplication {
public static void main(String[] args){
ApplicationContext context = SpringApplication.run(PackageTestApplication.class, args);
}
}
SayHelloController
@RequestMapping("/api/test")
@Slf4j
@RestController
@RequiredArgsConstructor
public class SayHelloController {
private final AppProperty mAppProperty;
@GetMapping("/hello")
public String sayHello(){
return mAppProperty.getMyName();
}
}
AppProperty
@Configuration
@ConfigurationProperties(prefix = "app")
@Data
public class AppProperty {
String myName;
}
application.yml
app:
my-name: test1
server:
# 服务端口
port: 8001
spring:
application:
name: "test"
logback.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<!-- 定义文件输出格式, 编码方式, 输出文件的路径 -->
<property name="pattern"
value="[%date{yyyy-MM-dd HH:mm:ss.SSS}] %X{logthreadId} %-5level %logger{80} %method %line - %msg%n"/>
<!-- magenta:洋红 boldMagenta:粗红 cyan:青色 white:白色 magenta:洋红 -->
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
<!-- <property name="CONSOLE_LOG_PATTERN"-->
<!-- value="%yellow(%date{yyyy-MM-dd HH:mm:ss})|%highlight(%-5level) |%blue(%thread) |%blue(%file:%line) |%green(%logger) |%cyan(%msg%n))"/>-->
<include resource="org/springframework/boot/logging/logback/defaults.xml"/>
<!-- 日志路径 -->
<property name="logPath" value="/approot/var/logs/package-test"/>
<property name="APP_NAME" value="package-test"/>
<property name="charsetEncoding" value="UTF-8"/>
<!-- 控制台输出 -->
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<!--日志级别过滤INFO以下-->
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>DEBUG</level>
</filter>
<encoder charset="GBK">
<!-- <pattern>[%d{yyyy-MM-dd HH:mm:ss.SSS}]-[%t]-[%C:%L]- %-5level-%m%n</pattern> -->
<pattern>${CONSOLE_LOG_PATTERN}</pattern>
</encoder>
</appender>
<!-- INFO 输出到文件 -->
<appender name="infoLog" class="ch.qos.logback.core.rolling.RollingFileAppender">
<append>true</append>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>
${logPath}/${APP_NAME}-INFO-%d{yyyy-MM-dd}_%i.log
</fileNamePattern>
<maxHistory>30</maxHistory>
<maxFileSize>100MB</maxFileSize>
</rollingPolicy>
<encoder>
<pattern>${pattern}</pattern>
<charset>${charsetEncoding}</charset>
</encoder>
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<!-- 设置日志输出级别 -->
<level>INFO</level>
</filter>
</appender>
<!-- WARN 输出到文件 -->
<appender name="warnLog" class="ch.qos.logback.core.rolling.RollingFileAppender">
<append>true</append>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>
${logPath}/${APP_NAME}-WARN-%d{yyyy-MM-dd}_%i.log
</fileNamePattern>
<maxHistory>30</maxHistory>
<maxFileSize>100MB</maxFileSize>
</rollingPolicy>
<encoder>
<pattern>${pattern}</pattern>
<charset>${charsetEncoding}</charset>
</encoder>
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<!-- 设置日志输出级别 -->
<level>WARN</level>
</filter>
</appender>
<!-- ERROR 输出到文件 -->
<appender name="errorLog" class="ch.qos.logback.core.rolling.RollingFileAppender">
<append>true</append>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>
${logPath}/${APP_NAME}-ERROR-%d{yyyy-MM-dd}_%i.log
</fileNamePattern>
<maxHistory>30</maxHistory>
<maxFileSize>100MB</maxFileSize>
</rollingPolicy>
<encoder>
<pattern>${pattern}</pattern>
<charset>${charsetEncoding}</charset>
</encoder>
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<!-- 设置日志输出级别 -->
<level>ERROR</level>
</filter>
</appender>
<!-- 优先级从高到低分别是 ERROR、WARN、INFO、DEBUG-->
<root level="INFO">
<appender-ref ref="console" />
<appender-ref ref="infoLog" />
<appender-ref ref="warnLog" />
<appender-ref ref="errorLog" />
</root>
<logger name="com.hzdl" level="DEBUG" additivity="false">
<appender-ref ref="console" />
<appender-ref ref="infoLog" />
<appender-ref ref="warnLog" />
<appender-ref ref="errorLog" />
</logger>
<logger name="org.springframework" level="INFO" additivity="false">
<appender-ref ref="console" />
<appender-ref ref="infoLog" />
<appender-ref ref="warnLog" />
<appender-ref ref="errorLog" />
</logger>
<logger name="com.tl" level="DEBUG" additivity="false">
<appender-ref ref="console" />
<appender-ref ref="infoLog" />
<appender-ref ref="warnLog" />
<appender-ref ref="errorLog" />
</logger>
</configuration>
三、打包设置
我们可以在pom的build模块做打包相关的设置
3.1 代码展示
先展示代码,然后再逐个讲解
<?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>indi.zhifa.recipe.test</groupId>
<artifactId>package</artifactId>
<version>1.0-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.13</version>
<relativePath/>
</parent>
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<package.version>1.0</package.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
<includes>
<include>*.yml</include>
<include>*.xml</include>
</includes>
</resource>
<resource>
<directory>src/main/resources/res</directory>
</resource>
</resources>
<plugins>
<!-- 分离资源文件 -->
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<executions>
<execution>
<id>copy-resources</id>
<phase>package</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<resources>
<resource>
<directory>src/main/resources/res</directory>
</resource>
</resources>
<outputDirectory>${project.build.directory}/resources</outputDirectory>
</configuration>
</execution>
<!-- <execution>-->
<!-- <id>copy-config</id>-->
<!-- <phase>package</phase>-->
<!-- <goals>-->
<!-- <goal>copy-resources</goal>-->
<!-- </goals>-->
<!-- <configuration>-->
<!-- <resources>-->
<!-- <resource>-->
<!-- <directory>src/main/resources</directory>-->
<!-- </resource>-->
<!-- </resources>-->
<!-- <outputDirectory>${project.build.directory}/../config</outputDirectory>-->
<!-- </configuration>-->
<!-- </execution>-->
</executions>
</plugin>
<!--打包jar-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<finalName>${project.name}-${package.version}</finalName>
<archive>
<!-- 指定资源文件目录,与打包的jar文件同级目录 -->
<manifestEntries>
<Class-Path>resources/</Class-Path>
</manifestEntries>
<manifest>
<addClasspath>true</addClasspath>
<!-- <classpathPrefix>lib/</classpathPrefix>-->
<mainClass>indi.zhifa.recipe.test.PackageTestApplication</mainClass>
</manifest>
</archive>
<!-- 打包时忽略的文件(也就是不打进jar包里的文件),本例将resources下的.yml、.properties文件全部排除 -->
<excludes>
<exclude>*.yml</exclude>
<exclude>*.properties</exclude>
<exclude>*.xml</exclude>
<exclude>static/**/*</exclude>
<exclude>templates/**/*</exclude>
</excludes>
</configuration>
</plugin>
<!-- spring boot repackage -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<finalName>${project.name}-${package.version}</finalName>
<layout>ZIP</layout>
<addResources>true</addResources>
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<finalName>${project.name}-${package.version}-assembly</finalName>
<appendAssemblyId>false</appendAssemblyId>
<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>
</plugins>
</build>
</project>
打包出来文件有这几个
3.2 assembly.xml
assembly.xml是关于打包的配置,代码中展示的是把target分别打包成tar.gz和zip。每一个fileSet表示压缩包中的一个文件夹。
第一个fileSet意思是把target目录下打包好的jar包复制到压缩包中的target文件夹
第二个fileSet意思是把target目录下的yml和xml复制到压缩包中的config文件夹
第三个fileSet意思是把target目录下resources文件夹复制到压缩包中的target/resource文件夹中
第四个fileSet意思是把${project.basedir}/bin目录下的所有文件复制到压缩包中的bin文件夹中
<!--具体含义参见官网 https://maven.apache.org/plugins/maven-assembly-plugin/assembly.html-->
<assembly>
<id>release</id>
<!--maven打包类型,当前为zip和tar.gz-->
<formats>
<format>tar.gz</format>
<format>zip</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<fileSets>
<fileSet>
<!--需要打包的文件所在路径-->
<directory>target</directory>
<!--需要打包的文件-->
<includes>
<include>*.jar</include>
</includes>
<!--打到压缩包的路径-->
<outputDirectory>./target</outputDirectory>
<fileMode>0755</fileMode>
</fileSet>
<fileSet>
<directory>${project.basedir}/target/classes</directory>
<outputDirectory>./config</outputDirectory>
<includes>
<include>*.yml</include>
<include>*.xml</include>
</includes>
<fileMode>0755</fileMode>
</fileSet>
<fileSet>
<directory>${project.basedir}/target/resources</directory>
<outputDirectory>./target/resource</outputDirectory>
<fileMode>0755</fileMode>
</fileSet>
<fileSet>
<directory>${project.basedir}/bin</directory>
<outputDirectory>./bin</outputDirectory>
<fileMode>0755</fileMode>
</fileSet>
</fileSets>
</assembly>
压缩包目录展示:
3.3 resources
这段代码表示
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
<includes>
<include>*.yml</include>
<include>*.xml</include>
</includes>
</resource>
<resource>
<directory>src/main/resources/res</directory>
</resource>
</resources>
这一代码段,是把resource下的数据复制到classes下。我们点击package,看一下效果
3.4 maven-resources-plugin
这个插件用于把target的class下文件复制到包中。
我们使用winrar打开package-1.0.jar,可以看到如下结构
BOOT-INF中,是存放代码,lib包以及资源的地方。
代码和资源放在class下,lib文件夹下放的是依赖的lib
org文件夹存放的Spring的加载器,META-INF存放maven相关
3.5 maven-jar-plugin
该插件主要是设定哪些资源文件不打如包中,这个好像不是SpringBoot的插件,但我没有找到更好的实现
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<finalName>${project.name}-${package.version}</finalName>
<archive>
<!-- 指定资源文件目录,与打包的jar文件同级目录 -->
<manifestEntries>
<Class-Path>resources/</Class-Path>
</manifestEntries>
<manifest>
<addClasspath>true</addClasspath>
<!-- <classpathPrefix>lib/</classpathPrefix>-->
<mainClass>indi.zhifa.recipe.test.PackageTestApplication</mainClass>
</manifest>
</archive>
<!-- 打包时忽略的文件(也就是不打进jar包里的文件),本例将resources下的.yml、.properties文件全部排除 -->
<excludes>
<exclude>*.yml</exclude>
<exclude>*.properties</exclude>
<exclude>*.xml</exclude>
<exclude>static/**/*</exclude>
<exclude>templates/**/*</exclude>
</excludes>
</configuration>
</plugin>
3.6 spring-boot-maven-plugin
这个插件必须写上,不然打包不成功。这个插件中可以设定打包出来的文件名
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<finalName>${project.name}-${package.version}</finalName>
<layout>ZIP</layout>
<addResources>true</addResources>
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
3.7 maven-assembly-plugin 与assembly.xml
前面的代码已经写了相关内容,这里不想赘述。
四、运行脚本
为了方便使用,还需加上运行脚本,这里直接给出代码,不再讲解
4.1 startup.cmd
@echo off
title bailan5.test1
set appName=bailan5.test1
if not exist "%JAVA_HOME%\bin\java.exe" echo Please set the JAVA_HOME variable in your environment, We need java(x64)! jdk11 or later is better! & EXIT /B 1
set JAVA=%JAVA_HOME%\bin\java.exe
setlocal enabledelayedexpansion
set BASE_DIR=%~dp0
set BASE_DIR=%BASE_DIR:~0,-5%
set JAR_NAME=test-1.0
set JAR_PATH=%BASE_DIR%\target
set CUSTOM_SEARCH_LOCATIONS=%BASE_DIR%\config/
set JAR_FULL=%JAR_PATH%\%JAR_NAME%.jar
set "JIM_OPT=-jar -Dfile.encoding=utf-8 %JAR_FULL%"
set "JIM_VM_OPT=-Xms512m -Xmx512m -Xmn256m"
set "JIM_CONFIG_OPT=--spring.config.location=file:%CUSTOM_SEARCH_LOCATIONS%"
set "JIM_LOG_OPT=--logging.config=file:%CUSTOM_SEARCH_LOCATIONS%logback.xml"
set "JIM_ENCODING=-Dfile.encoding=utf-8"
set COMMAND=%JAVA% %JIM_VM_OPT% %JIM_OPT% %JIM_ENCODING% %JIM_CONFIG_OPT% %JIM_LOG_OPT% %appName% %*
echo %BASE_DIR%
echo %COMMAND%
pause
%COMMAND%
注意,这里有个坑。为了支持yml里有中文,必须使用java -jar -Dfile.encoding=utf-8 XXX.jar来启动。然而,这种方式在win11的powershell中会报错,用基本的cmd启动则没有问题。
4.2 startup.sh
#!/bin/bash
cygwin=false
darwin=false
os400=false
case "`uname`" in
CYGWIN*) cygwin=true;;
Darwin*) darwin=true;;
OS400*) os400=true;;
esac
error_exit ()
{
echo "ERROR: $1 !!"
exit 1
}
[ ! -e "$JAVA_HOME/bin/java" ] && JAVA_HOME=$HOME/jdk/java
[ ! -e "$JAVA_HOME/bin/java" ] && JAVA_HOME=/usr/java
[ ! -e "$JAVA_HOME/bin/java" ] && unset JAVA_HOME
if [ -z "$JAVA_HOME" ]; then
if $darwin; then
if [ -x '/usr/libexec/java_home' ] ; then
export JAVA_HOME=`/usr/libexec/java_home`
elif [ -d "/System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK/Home" ]; then
export JAVA_HOME="/System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK/Home"
fi
else
JAVA_PATH=`dirname $(readlink -f $(which javac))`
if [ "x$JAVA_PATH" != "x" ]; then
export JAVA_HOME=`dirname $JAVA_PATH 2>/dev/null`
fi
fi
if [ -z "$JAVA_HOME" ]; then
error_exit "Please set the JAVA_HOME variable in your environment, We need java(x64)! jdk8 or later is better!"
fi
fi
export SERVER="package-1.0"
export SERVER_JAR="package-1.0.jar"
export JAVA_HOME
export JAVA="$JAVA_HOME/bin/java"
export BASE_DIR=`cd $(dirname $0)/..; pwd`
export CUSTOM_SEARCH_LOCATIONS=file:${BASE_DIR}/config/
#===========================================================================================
# JVM Configuration
#===========================================================================================
JAVA_OPT="${JAVA_OPT} -Xms512m -Xmx512m -Xmn256m"
JAVA_OPT="${JAVA_OPT} ${JAVA_OPT_EXT}"
JAVA_OPT="${JAVA_OPT} -jar ${BASE_DIR}/target/${SERVER_JAR}"
JAVA_OPT="${JAVA_OPT} --spring.config.additional-location=${CUSTOM_SEARCH_LOCATIONS}"
JAVA_OPT="${JAVA_OPT} --logging.config=${BASE_DIR}/config/logback.xml"
JAVA_OPT="${JAVA_OPT} --server.max-http-header-size=524288"
JAVA_MAJOR_VERSION=$($JAVA -version 2>&1 | sed -E -n 's/.* version "([0-9]*).*$/\1/p')
if [[ "$JAVA_MAJOR_VERSION" -ge "9" ]] ; then
JAVA_OPT="${JAVA_OPT} -Xlog:gc*:file=${BASE_DIR}/logs/nacos_gc.log:time,tags:filecount=10,filesize=102400"
else
JAVA_OPT="${JAVA_OPT} -Djava.ext.dirs=${JAVA_HOME}/jre/lib/ext:${JAVA_HOME}/lib/ext"
JAVA_OPT="${JAVA_OPT} -Xloggc:${BASE_DIR}/logs/nacos_gc.log -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCTimeStamps -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=10 -XX:GCLogFileSize=100M"
fi
JAVA_OPT="${JAVA_OPT} -Dloader.path=${BASE_DIR}/plugins/health,${BASE_DIR}/plugins/cmdb"
JAVA_OPT="${JAVA_OPT} -Dnacos.home=${BASE_DIR}"
JAVA_OPT="${JAVA_OPT} -jar ${BASE_DIR}/target/${SERVER}.jar"
if [ ! -d "${BASE_DIR}/logs" ]; then
mkdir ${BASE_DIR}/logs
fi
echo "$JAVA ${JAVA_OPT}"
# start
echo "$JAVA ${JAVA_OPT}" > ${BASE_DIR}/logs/start.out 2>&1 &
nohup $JAVA ${JAVA_OPT} bailan5.package-test >> ${BASE_DIR}/logs/start.out 2>&1 &
echo "bailan5.package-test is starting,you can check the ${BASE_DIR}/logs/start.out"
4.3 shutdown.cmd
@echo off
if not exist "%JAVA_HOME%\bin\java.exe" echo Please set the JAVA_HOME variable in your environment, We need java(x64)! jdk11 or later is better! & EXIT /B 1
setlocal
set "PATH=%JAVA_HOME%\bin;%PATH%"
echo killing bailan5.package-test
for /f "tokens=1" %%i in ('jps -m ^| find "bailan5.package-test"') do ( taskkill /F /PID %%i )
echo Done!
4.4 shutdown.sh
cd `dirname $0`/../target
target_dir=`pwd`
pid=`ps ax | grep -i 'bailan5.package-test' | grep ${target_dir} | grep java | grep -v grep | awk '{print $1}'`
if [ -z "$pid" ] ; then
echo "No bailan5.package-test running."
exit 0;
fi
echo "The bailan5.package-test(${pid}) is running..."
kill ${pid}
echo "Send shutdown request to bailan5.package-test(${pid}) OK"