由于springboot项目一般是以jar包形式运行,默认是将依赖的jar包一起打包到程序中,部署时传输的文件比较大。所以我们可以将程序的jar包、lib库、配置文件分离开来,方面升级部署。
一、用到的插件
1、spring-boot-maven-plugin插件
这个是springboot的插件,会将项目所有的依赖打入BOOT-INF/lib
2、maven-jar-plugin插件
打包时分离程序和依赖包
3、maven-dependency-plugin插件
将依赖包复制到lib目录下
4、maven-resources-plugin插件
复制配置文件到target/classes/config目录
5、maven-assembly-plugin插件
将配置文件复制到config目录下,然后将程序、lib目录、config目录,打成zip压缩包
二、pom.xml文件修改
1、注释原来的打包插件
<!-- 打包成jar的插件,项目可用java -jar xxx.jar运行 -->
<!--
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
-->
原来整体打包出来的目录结构:
2、使用maven-jar-plugin来打包
<!-- 打包时分离程序和依赖包 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifest>
<!--是否要把第三方jar放到manifest.mf的classpath中 -->
<addClasspath>true</addClasspath>
<!--生成的manifest.mf中classpath的前缀,因为要把第三方jar放到lib目录下,所以classpath的前缀是lib/ -->
<classpathPrefix>lib/</classpathPrefix>
<!-- 执行的主程序路径 -->
<mainClass>com.example.myboot.MybootApplication</mainClass>
</manifest>
</archive>
<!-- 排除target/classes下的config目录 -->
<excludes>
<exclude>config/**</exclude>
</excludes>
</configuration>
</plugin>
分离依赖包后的目录结构:
3、不打包配置文件
<resources>
<!-- 打包加入资源文件 -->
<resource>
<directory>src/main/resources</directory>
<!-- 资源独立出来,打包时排除这些配置文件类型和resources下的其他目录 -->
<excludes>
<exclude>*.yml</exclude>
<exclude>*.properties</exclude>
<exclude>*.xml</exclude>
<exclude>generator/**</exclude>
<exclude>assembly/**</exclude>
</excludes>
</resource>
<!-- 读取webapp下的静态文件 -->
<resource>
<directory>src/main/webapp</directory>
<targetPath>META-INF/resources</targetPath>
</resource>
</resources>
分离配置文件后的目录结构:
4、使用maven-resources-plugin复制资源文件
<!-- 拷贝src/main/resources下的配置文件到target/classes/config目录下,这样本地和junit能跑起来 -->
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<executions>
<execution>
<id>copy-config</id>
<phase>process-sources</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>target/classes/config</outputDirectory>
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>*.yml</include>
<include>*.properties</include>
<include>*.xml</include>
</includes>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
5、使用maven-dependency-plugin复制依赖包到lib目录下
<!-- 拷贝依赖到jar外面的lib目录 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>copy-lib</id>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<!-- 输出路径 -->
<outputDirectory>target/lib</outputDirectory>
<!-- 排除传递依赖 -->
<excludeTransitive>false</excludeTransitive>
<!-- 复制的jar文件是否去掉版本信息 -->
<stripVersion>false</stripVersion>
<!-- 包含scope的范围 -->
<includeScope>runtime</includeScope>
</configuration>
</execution>
</executions>
</plugin>
6、使用maven-assembly-plugin整体打包成zip文件
<!-- 将配置文件复制到config目录下,然后将程序、lib目录、config目录,打成zip压缩包 -->
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<!-- 打包后的包名是否包含assembly的id名 -->
<appendAssemblyId>false</appendAssemblyId>
<!-- 引用的assembly配置文件 -->
<descriptors>
<descriptor>src/main/resources/assembly/assembly.xml</descriptor>
</descriptors>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<!-- 绑定到package生命周期阶段上 -->
<phase>package</phase>
<!-- 运行一次 -->
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
在src/main/resources下建立assembly目录,新建assembly.xml:
<assembly
xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3 http://maven.apache.org/xsd/assembly-1.1.3.xsd">
<id>package</id>
<formats>
<format>zip</format>
</formats>
<includeBaseDirectory>true</includeBaseDirectory>
<fileSets>
<!-- 将代码目录/src/main/resources下的文件,复制到输出目录的config内 -->
<fileSet>
<directory>${basedir}/src/main/resources</directory>
<includes>
<include>*.yml</include>
<include>*.properties</include>
<include>*.xml</include>
</includes>
<filtered>true</filtered>
<outputDirectory>${file.separator}config</outputDirectory>
</fileSet>
<!-- 将构建目录/lib下的文件,复制到输出目录的lib内 -->
<fileSet>
<directory>${project.build.directory}/lib</directory>
<outputDirectory>${file.separator}lib</outputDirectory>
<includes>
<include>*.jar</include>
</includes>
</fileSet>
<!-- 将构建目录根目录下的jar包,复制到输出目录的根目录下 -->
<fileSet>
<directory>${project.build.directory}</directory>
<outputDirectory>${file.separator}</outputDirectory>
<includes>
<include>*.jar</include>
</includes>
</fileSet>
</fileSets>
</assembly>
zip解压后有两个目录和一个jar文件:
三、配置外部logback配置文件
由于配置文件放到config目录后,springboot默认读取logback.xml读不到了
在application.yml添加:
#配置外部logback.xml
logging:
config: classpath:./config/logback.xml
在ide里run起来和执行junit需要用classpath,classpath路径是target/classes下,所以能找到logback的配置文件,但是放到服务器上部署,则需要相对文件的路径,这一点暂时没能统一。。
#配置外部logback.xml
logging:
config: file:./config/logback.xml
file在ide中是项目根目录,在执行jar文件时就是其本身目录。所以ide中读不到,服务器部署时能读到
解决办法看这里:https://blog.csdn.net/csj50/article/details/120196041
四、启动项目命令
java -jar myboot-0.0.1-SNAPSHOT.jar --spring.config.location=file:./config/
五、完整的pom.xml文件
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<!-- 核心配置,包含默认依赖 -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.8.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>myboot</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>myboot</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<maven-jar-plugin.version>3.1.1</maven-jar-plugin.version>
</properties>
<dependencies>
<!-- 模板引擎thymeleaf -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!-- web场景的依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 测试依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
<!-- mybatis依赖 -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.1</version>
</dependency>
<!-- mysql驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.19</version>
</dependency>
<!-- druid数据库连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.21</version>
</dependency>
<!-- tkMybatis -->
<dependency>
<groupId>tk.mybatis</groupId>
<artifactId>mapper-spring-boot-starter</artifactId>
<version>2.1.5</version>
</dependency>
<!-- 分页插件 -->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.2.13</version>
</dependency>
<!--redis启动器 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- 连接池 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<!-- springcache缓存 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<!-- spring session依赖 -->
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>30.1-jre</version>
</dependency>
<!-- 自定义starter包 -->
<dependency>
<groupId>com.example</groupId>
<artifactId>sms-spring-boot-starter</artifactId>
<version>1.0.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<!-- 打包成jar的插件,项目可用java -jar xxx.jar运行 -->
<!--
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
-->
<!-- 打包时分离程序和依赖包 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifest>
<!--是否要把第三方jar放到manifest.mf的classpath中 -->
<addClasspath>true</addClasspath>
<!--生成的manifest.mf中classpath的前缀,因为要把第三方jar放到lib目录下,所以classpath的前缀是lib/ -->
<classpathPrefix>lib/</classpathPrefix>
<!-- 执行的主程序路径 -->
<mainClass>com.example.myboot.MybootApplication</mainClass>
</manifest>
</archive>
<!-- 排除target/classes下的config目录 -->
<excludes>
<exclude>config/**</exclude>
</excludes>
</configuration>
</plugin>
<!-- 拷贝src/main/resources下的配置文件到target/classes/config目录下,这样本地和junit能跑起来 -->
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<executions>
<execution>
<id>copy-config</id>
<phase>process-sources</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>target/classes/config</outputDirectory>
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>*.yml</include>
<include>*.properties</include>
<include>*.xml</include>
</includes>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
<!-- 拷贝依赖到jar外面的lib目录 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>copy-lib</id>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<!-- 输出路径 -->
<outputDirectory>target/lib</outputDirectory>
<!-- 排除传递依赖 -->
<excludeTransitive>false</excludeTransitive>
<!-- 复制的jar文件是否去掉版本信息 -->
<stripVersion>false</stripVersion>
<!-- 包含scope的范围 -->
<includeScope>runtime</includeScope>
</configuration>
</execution>
</executions>
</plugin>
<!-- 将配置文件复制到config目录下,然后将程序、lib目录、config目录,打成zip压缩包 -->
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<!-- 打包后的包名是否包含assembly的id名 -->
<appendAssemblyId>false</appendAssemblyId>
<!-- 引用的assembly配置文件 -->
<descriptors>
<descriptor>src/main/resources/assembly/assembly.xml</descriptor>
</descriptors>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<!-- 绑定到package生命周期阶段上 -->
<phase>package</phase>
<!-- 运行一次 -->
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- idea下有用 -->
<plugin>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>1.4.0</version>
<configuration>
<configurationFile>${basedir}/src/main/resources/generator/generatorConfig.xml</configurationFile>
<overwrite>true</overwrite>
<verbose>true</verbose>
</configuration>
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.19</version>
</dependency>
</dependencies>
</plugin>
</plugins>
<resources>
<!-- 打包加入资源文件 -->
<resource>
<directory>src/main/resources</directory>
<!-- 资源独立出来,打包时排除这些配置文件类型和resources下的其他目录 -->
<excludes>
<exclude>*.yml</exclude>
<exclude>*.properties</exclude>
<exclude>*.xml</exclude>
<exclude>generator/**</exclude>
<exclude>assembly/**</exclude>
</excludes>
</resource>
<!-- 读取webapp下的静态文件 -->
<resource>
<directory>src/main/webapp</directory>
<targetPath>META-INF/resources</targetPath>
</resource>
</resources>
</build>
</project>
六、小结
整体思路:
1、分离程序、配置文件、依赖包
2、但是由于项目需要本机run起来和junit测试,所以target/classes/下需要有配置文件
打包时先排除了配置文件和依赖包
然后用maven-resources-plugin插件把配置文件复制到target/classes/config目录下
用maven-dependency-plugin插件把依赖包复制到target/classes/lib目录下
3、打包时再排除target/classes下的config目录
七、其他
<exclude>config/*</exclude>和<exclude>config/**</exclude>的区别:
一个星号,打包后,会排除config下的文件,但是config目录还在,是一个空目录。两个星号就没有config这个空目录了
参考资料:
maven pom 配置 学习笔记(五)之 maven-jar-plugin - 夏之夜 - 博客园
SpringBoot打包优化_liusong3514的博客-CSDN博客_springboot 打包优化
SpringBoot打包将lib分开打包_猫猫Black的博客-CSDN博客
Spring MVC中Filter Servlet Interceptor 执行顺序_lisheng19870305的专栏-CSDN博客
注:最新代码上传至https://github.com/csj50/myboot