war包
在相对传统的场景下,可能需要将spring boot web应用的包war包,部署到诸如Tomcat等容器中,我们可以借助maven插件完成打包。
打包
修改bootapp的打包方式为war:
<packaging>war</packaging>
在maven依赖列表中更改spring-boot-starter-tomcat
的scope为provided
,这样spring-boot-maven-plugin
不会将tomact相关写打入WEB-INF/lib
,而是将tomcat相关包写入WEB-INF/lib-provided
,这样容器在启动war包时只会加载WEB-INF/lib
下的依赖,其他文件夹的依赖会被忽略。
不用从koca-boot-standalone-starter
或koca-boot-cloud-starter
中显式地排除tomacat相关的包,在依赖列表中重新引入一次即可:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
添加maven-war-plugin
:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>3.1.0</version>
</plugin>
最好指定版本(3.1.0+
),较低版本在没有指定web.xml
时打包可能会报错找不到web.xml,传统的war包需要在web.xml中定义servlet、filter、contextPath等web相关的组件,但在spring boot应用中可以委托给spring来完成,不需要显式定义web.xml,低版本的maven-war-plugin
可以如下配置来避免这个问题:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>3.1.0</version>
<configuration>
<!-- 没有web.xml时不报错 -->
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
如果确实有WEB-INF/web.xml
配置,插件打包时会自动打入war包,也可用<webXml>
配置指定路径。
对于jboss
或 wildfly
容器,可能还需要单独的配置,因为jboss在JDK9+环境下没有暴露sun.reflect
和 jdk.internal
包,导致spring初始化没有无参构造方法的实例时报java.lang.NoSuchMethodException:......<init>()
:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<archive>
<manifestEntries>
<!-- 告知jboss暴露相关包 -->
<Dependencies>jdk.unsupported</Dependencies>
</manifestEntries>
</archive>
</configuration>
</plugin>
另外jboss对日志配置检测非常严格,当classpath有多个Logger实现时,jboss会启动war包失败,比如同时引用了log4j和logback,在IDE或tomcat中最多抛出警告日志,但jboss会直接失败,因此注意排除类路径中日志系统的冲突,只保留一个日志实现。
添加spring-boot-maven-plugin
,此插件用于完成可执行war、启动时注册Servlet等操作:
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<id>default</id>
<phase>package</phase>
<goals>
<goal>build-info</goal>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
由于默认的war包会带上版本(my-project-1.0.0-SNAPSHOT.war
),但是tomcat等容器会直接使用war包包名作为context-path,可以在<build>
标签中指定文件名称:
<build>
<finalName>myproject</finalName>
</build>
最后调整一下启动类,使用内嵌的tomcat时,spring boot自动将servlet等信息注册到内嵌tomcat,但是打成war包后,又没有配置web.xml,所以需要在启动时把servlet信息注册到容器中:
SpringBootApplication
public class Application extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(Application.class);
}
public static void main(String[] args) {
new SpringApplication(Application.class).run(args);
}
}
只需启动类继承SpringBootServletInitializer
并覆盖configure方法即可。
最后的使用mvn clean package
打包后,就可在编译目录输出myproject.war
。
整个pom配置如下:
<?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>
<parent>
<groupId>szkingdom.yf.koca.parent</groupId>
<artifactId>koca-parent</artifactId>
<version>2.4.0-RELEASE</version>
<relativePath/>
</parent>
<groupId>org.example</groupId>
<artifactId>myproject</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<dependencies>
<!-- your dependencies -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<finalName>myproject</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>3.1.0</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
<archive>
<manifestEntries>
<Dependencies>jdk.unsupported</Dependencies>
</manifestEntries>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<id>default</id>
<phase>package</phase>
<goals>
<goal>build-info</goal>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
部署
‘Fatwar’
和fatjar一样,使用spring-boot-maven-plugin
的打出的war包也可以不依赖外部servlet 容器,直接使用java -jar a.war
tomcat
将war包拷贝至webapps目录下,重启tomcat,可以通过localhost:${tomcat.port}/${war.package.name}/${api.path}
访问该服务,注意server.port
和server.servlet.context-path
配置将失效。
wildfly(jboss/undertow)
将war包拷贝至standalone/deployments目录,重启jboos,可通过127.0.0.1:${jboss.port}/${war.package.name}/${api.path}
访问该服务,注意server.port
和server.servlet.context-path
配置将失效。