在代码依赖过多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: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