芝法酱躺平攻略(13)——SpringBoot打包Config与Resource的分离

1 篇文章 0 订阅
1 篇文章 0 订阅

一、前言

后面我们打算探索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"
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值