spring boot 打jar包分离lib和resources

在代码依赖过多jar包,或者频繁修改resources目录下的配置文件时,直接把所有信息打到jar里面会非常麻烦。可以通过打jar包分离lib和resources的方式来解决这个问题。

在配置完成之后,启动项目出现了错误

2019-06-21 14:12:13.088 DirectJDKLog.java:182 - A child container failed during startjava.util.concurrent.ExecutionException: org.apache.catalina.LifecycleException: Failed to start component [StandardEngine[Tomcat].StandardHost[localhost].TomcatEmbeddedContext[]] at java.util.concurrent.FutureTask.report(Unknown Source) ~[?:1.8.0_121] at java.util.concurrent.FutureTask.get(Unknown Source) ~[?:1.8.0_121] at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:941) ~[tomcat-embed-core-8.5.31.jar!/:8.5.31] at org.apache.catalina.core.StandardHost.startInternal(StandardHost.java:872) ~[tomcat-embed-core-8.5.31.jar!/:8.5.31] at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150) ~[tomcat-embed-core-8.5.31.jar!/:8.5.31] at org.apache.catalina.core.ContainerBaseStartChild.call(ContainerBase.java:1421) ~[tomcat-embed-core-8.5.31.jar!/:8.5.31] at org.apache.catalina.core.ContainerBaseStartChild.call(ContainerBase.java:1411) ~[tomcat-embed-core-8.5.31.jar!/:8.5.31] at java.util.concurrent.FutureTask.run(Unknown Source) ~[?:1.8.0_121] at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source) ~[?:1.8.0_121] at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) ~[?:1.8.0_121] at java.lang.Thread.run(Unknown Source) [?:1.8.0_121]Caused by: org.apache.catalina.LifecycleException: Failed to start component [StandardEngine[Tomcat].StandardHost[localhost].TomcatEmbeddedContext[]] at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:167) ~[tomcat-embed-core-8.5.31.jar!/:8.5.31] ... 6 more

看错误提示跟tomcat有关。找到相关依赖,我这里依赖引用了javax.servlet-api.

<dependency>

 <groupId>javax.servlet</groupId> 

<artifactId>javax.servlet-api</artifactId> 

<version>${javax.servlet-api.version}</version>   

</dependency> 

解决方式是设置<scope>provided </scope>

scope默认是compile,也就是说这个项目在编译,测试,运行阶段都需要这个artifact对应的jar包在classpath中。scope设置为provided,表示这个provided是目标容器已经provide这个依赖。

执行mvn install命令生成目录结构如下: lib,resources,xxx.jar.

打包完成后的目录由三部分组成

配置代码如下:

<plugins>
   
            <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>
                            <!-- 依赖包输出目录,将来不打进jar包里 -->
                            <outputDirectory>${project.build.directory}/lib</outputDirectory>
                            <excludeTransitive>false</excludeTransitive>
                            <stripVersion>false</stripVersion>
                            <includeScope>runtime</includeScope>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
   
            <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
                <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>
                                </resource>
                            </resources>
                            <outputDirectory>${project.build.directory}/resources</outputDirectory>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>*.yml</exclude>
                        <exclude>*.properties</exclude>
                        <exclude>*.xml</exclude>
                        <exclude>*.docx</exclude>
                        <exclude>*.txt</exclude>
                        <exclude>liquibase/**</exclude>
                        <exclude>mapper/**</exclude>
                        <exclude>META-INF/**</exclude>
                    </excludes>
                </configuration>
            </plugin>
            
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <layout>ZIP</layout>
                    <includes>
                        <include>
                            <groupId>non-exists</groupId>
                            <artifactId>non-exists</artifactId>
                        </include>
                    </includes>
                    <fork>true</fork>
                </configuration>
                <executions>
                    <execution>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
</plugins>

对上面几个plugin简单说明,详细使用方式可以分别百度相关用法。

1.maven-dependency-plugin是处理与依赖相关的插件。它有很多可用的goal,大部分是和依赖构建、分析和解决相关的goal,这部分goal可以直接用maven的命令操作,这里我们使用了copy-dependencies,这样就把所有的依赖jar打包到了lib目录下。

2.maven-resources-plugin负责处理项目资源文件并拷贝到输出目录。
Resources插件目标有三个:

resources:resources:用来将目录中的资源文件src/main/resources拷贝到编译目录${project.build.outputDirectory}。这个目标默认绑定到了Maven的process-resources阶段,所以process-resources阶段被执行,这个目标就会自动触发。

resources:testResources:用来将目录中的资源文件src/test/resources拷贝到编译目录${project.build.testOutputDirectory}。这个目标默认绑定到了Maven的process-test-resources阶段,所以process-test-resources阶段被执行,这个目标就会自动触发。

resources:copy-resources:用来将指定目录中的资源文件拷贝到指定目录,注意需要自己设置资源文件目录和目标目录。

3.maven-jar-plugin这里我们排除掉不打到jar包里面的文件。

4.spring-boot-maven-plugin 能够将Spring Boot应用打包为可执行的jar或war文件,然后以通常的方式运行Spring Boot应用。
Spring Boot Maven plugin的5个Goals

spring-boot:repackage,默认goal。在mvn package之后,再次打包可执行的jar/war,同时保留mvn package生成的jar/war为.origin
spring-boot:run,运行Spring Boot应用
spring-boot:start,在mvn integration-test阶段,进行Spring Boot应用生命周期的管理
spring-boot:stop,在mvn integration-test阶段,进行Spring Boot应用生命周期的管理
spring-boot:build-info,生成Actuator使用的构建信息文件build-info.properties

注意,这里的layout属性值为ZIP
layout属性的值可以如下:

JAR,即通常的可执行jar。Main-Class: org.springframework.boot.loader.JarLauncher
WAR,即通常的可执行war,需要的servlet容器依赖位于WEB-INF/lib-provided。Main-Class: org.springframework.boot.loader.warLauncher
ZIP,即DIR,类似于JAR。Main-Class: org.springframework.boot.loader.PropertiesLauncher
MODULE,将所有的依赖库打包(scope为provided的除外),但是不打包Spring Boot的任何Launcher
NONE,将所有的依赖库打包,但是不打包Spring Boot的任何Launcher

最终多模块目录结构

启动方式:

 前台运行:
        java -jar -Dloader.path=.,resources,lib xxx.jar
    后台运行和日志目录:
        nohup java -jar -Dloader.path=.,resources,lib xxx.jar >/xxx/log/xxx-out.log &

详细代码可以参考码云

linux启动脚本xxxx.sh

#!bin/bash
#你的可执行jar:XXXXX.jar
EXECUTABLE_JAR=XXXXX.jar

#使用说明,用来提示输入参数
explain() {
 echo "启动命令:sh xxxx.sh  start|停止命令: sh xxxx.sh stop"
 exit 1
}

#检查程序是否在运行
is_exist(){
 pid=`ps -ef|grep $EXECUTABLE_JAR|grep -v grep|awk '{print $2}' `
  #如果支持lsof命令可以直接替换成pid=`lsof -i :端口号`
 #如果不存在返回1,存在返回0
 if [ -z "${pid}" ]; then
 return 1
 else
 return 0
 fi
}
#启动方法
start(){
 is_exist
 if [ $? -eq "0" ]; then
         echo "${EXECUTABLE_JAR} is already running. pid=${pid} ."
 else
        nohup java -jar -Dloader.path=.,resources,lib $EXECUTABLE_JAR>/home/data/xxxx/log/xxxx-out.log 2>&1 &
 echo "${EXECUTABLE_JAR} start success"
 fi
}



#停止方法
stop(){
 is_exist
 if [ $? -eq "0" ]; then
         kill -9 $pid
 else
 echo "${EXECUTABLE_JAR} stop success"
 fi
}


#根据输入参数,选择执行对应方法,不输入则执行使用说明
case "$1" in
   "start")
    start
  ;;
   "stop")
    stop
 ;;
*)
 explain
 ;;
esac


最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,378评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,356评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,702评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,259评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,263评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,036评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,349评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,979评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,469评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,938评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,059评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,703评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,257评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,262评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,485评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,501评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,792评论 2 345