Spring Boot 项目打包静态资源分离实践

Spring Boot 打包远程执行代码
placeholder image
admin 发布于:2023-02-19 10:16:16
阅读:loading

1.基本介绍

前面一篇《Spring Boot 项目assembly打包实践》介绍了非常高端的企业级打包实战,自以为是非常完美的,然而最终还是被水平限制了,其中重要的一点是没有将静态资源给剥离出来,当时属实不知道剥离出来后可以起到热更新的作用,所以也就没有认识到有非常高的必要性,直到前天在友链站点看到了《spring boot项目使用maven插件将项目和jar包依赖以及静态资源分离打包》这篇文章(实际之前也看到过几次),专门留言问了一下是否能够支持资源文件的热更新,得到博主的肯定回复,不禁又来了兴趣,所以就有了关于项目打包的本篇文章和后续一篇。

实际在前三四年前最初体验到Spring Boot项目工程的部署运行时,当时的所有资源文件均在于一个jar(并不是仅一个jar包),当时提出了一个意见就是前台的项目打个war包要比这种jar包要合理啊,毕竟war包中的前端资源文件更改了可以立即生效,得到不认可的态度,也认为war是过失淘汰的产物,不过我还是认为存在就有它的合理性,选择合理的时机应用即可,毕竟这几年以来前台项目稍微变更一丢丢都需要走部署上线的流程。

本次实践重点在于改造博客示例项目的代码,调整打包实现,将静态资源(image,css,js等)和thymeleaf的template模板资源从jar包中拆离出去,前者是直接使用浏览器访问的,后者是需要访问controller地址后进行的页面跳转,来验证这些文件是否能够热更新,实际还有一些类似Excel导出模板和Freemarker的模板是否支持热更新,未作验证,详细过程参考下文。

2.项目结构

image.png

3.打包命令

<build>

    <plugins>
        <!-- 打JAR包 -->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-jar-plugin</artifactId>
            <configuration>
                <!-- 不打包资源文件(配置文件和依赖包分开) -->
                <excludes>
                    <exclude>*.yaml</exclude>
                    <exclude>*.xml</exclude>
                    <exclude>prod/**</exclude>
                    <exclude>test/**</exclude>
                    <exclude>config/**</exclude>
                </excludes>
                <archive>
                    <manifest>
                        <addClasspath>true</addClasspath>
                        <!-- MANIFEST.MF 中 Class-Path 加入前缀 -->
                        <classpathPrefix>lib</classpathPrefix>
                        <!-- jar包不包含唯一版本标识 -->
                        <useUniqueVersions>false</useUniqueVersions>
                        <!--指定入口类 -->
                        <mainClass>cn.chendd.Bootstrap</mainClass>
                    </manifest>
                    <manifestEntries>
                        <!--MANIFEST.MF 中 Class-Path 加入资源文件目录 -->
                        <Class-Path>conf/</Class-Path>
                    </manifestEntries>
                </archive>
                <outputDirectory>${project.build.directory}</outputDirectory>
            </configuration>
        </plugin>
        <!-- 该插件的作用是用于复制依赖的jar包到指定的文件夹里 -->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-dependency-plugin</artifactId>
            <executions>
                <execution>
                    <id>copy-dependencies</id>
                    <phase>package</phase>
                    <goals>
                        <goal>copy-dependencies</goal>
                    </goals>
                    <configuration>
                        <outputDirectory>${project.build.directory}/lib/</outputDirectory>
                    </configuration>
                </execution>
            </executions>
        </plugin>

        <!-- 该插件的作用是用于复制指定的文件 -->
        <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</directory>
                                <includes>
                                    <include>*/**</include>
                                </includes>
                                <excludes>
                                    <exclude>prod/**</exclude>
                                    <exclude>test/**</exclude>
                                </excludes>
                            </resource>
                            <resource>
                                <directory>src/main/views</directory>
                                <includes>
                                    <include>*/**</include>
                                </includes>
                            </resource>
                        </resources>
                        <outputDirectory>${project.build.directory}/conf</outputDirectory>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

【脚本说明】

(1)manifest节点中定义了mainClass主启动类,以当前模块admin打包为admin.jar为主核心jar文件,classpathPrefix标签定义了主jar所依赖的其它目录的文件夹结构层级,如果该标签配置空白字符,则表示admin.jar要与其它依赖的jar隶属于同级目录;

(2)Class-Path目录定义了资源配置文件与主admin.jar的目录层级,若属于同级目录则可为“conf/”,所为上级目录可为“../conf/”,必须以/结尾;

(3)如果定义了这两个目录,打包时将严格按照这些配置生效,它们决定了最终的启动命令,如可以使用java -jar admin-1.0-SNAPSHOT.jar直接运行,可以不用指定“-Dloader.path=conf,lib”;具体的打包命令和打包时的上述两个参数有严格的依赖关系,目录结构要严格匹配,假如启动命令是以打包目录中的bin目录执行的,则打包命令参考为:“java -jar ../lib/admin-1.0-SNAPSHOT.jar”,此时说明,主jar包admin.jar与其它依赖jar均属于lib目录下,且lib目录与conf目录同级别,所以上述的两个参数中classpathPrefix的值应该是“”,Class-Path的值应该是“../conf/”;

(4)打包命令参考为:“clean compile package -Dmaven.test.skip=true -f pom.xml”,也可以在IDEA中右侧maven面板中,进行打包;

4.打包结果

image.png

【打包说明】

(1)除了框起来的conf和lib及admin-1.0-SNAPSHOT.jar以外的其它文件夹均可删除;

(2)精简后的目录在运行后输出logs文件夹,该文件夹为日志的输出路径,参考如下:

image.png

5.运行结果

打包热部署.gif

【运行说明】

(1)conf目录为静态资源目录和配置文件目录,其中statics为静态资源目录,templates为thymeleaf模板路径其它路径为classes中的配置文件

(2)修改statics路径下的readme.txt文件,验证更新生效;

(3)在statics路径下增加lhk.jpg文件,验证增加文件生效;

(4)在templates目录下的usage目录的simple.html更新,验证修改模板文件生效(该文件内部有包含thymeleaf标签);

(5)本例验证项目源码可见:https://gitee.com/88911006/chendd-blog-examples项目的“PackageJarResources”分支;

(6)本例的实践定位是小试项目打包资源的分离,后文将会有更加专业和更具维护的企业级应用打包实践;


 点赞


 发表评论

当前回复:作者

 评论列表


留言区