Springboot项目通常打包为jar,直接就可以运行,还是比较方便的。但是最近项目需要将springboot项目打包成war,放到单独的tomcat中进行运行,还是有好些需要注意的地方。
1、继承SpringBootServletInitializer
外部容器部署,此时需要在启动类中继承SpringBootServletInitializer并实现configure方法,并且在application.sources方法传入启动类。
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
@SpringBootApplication
public class WarDemoApplication extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(WarDemoApplication.class);
}
public static void main(String[] args) {
SpringApplication.run(WarDemoApplication.class, args);
}
}
2、pom.xml修改tomcat相关的配置
如果要将最终的打包形式改为war的话,还需要对pom.xml文件进行修改,因为spring-boot-starter-web中包含内嵌的tomcat容器,所以直接部署在外部容器会冲突报错。
这里有两种方法可以解决,如下
方法一:移除Tomcat依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
在这里需要移除对嵌入式Tomcat的依赖,这样打出的war包中,在lib目录下才不会包含Tomcat相关的jar包。
还有一个很关键的关键点,就是tomcat-embed-jasper中scope必须是provided。
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<scope>provided</scope>
</dependency>
因为SpringBootServletInitializer需要依赖 javax.servlet,而tomcat-embed-jasper下面的tomcat-embed-core中就有这个javax.servlet,如果没用provided,最终打好的war里面会有servlet-api这个jar,这样就会跟tomcat本身的冲突了。
方法二:将Tomcat配置为provided
spring-boot-starter-tomcat是Spring Boot默认就会配置的,即Spring Boot的内嵌tomcat,将其设置为provided是在打包时会将该包(依赖)排除,因为要放到独立的tomcat中运行,Spring Boot内嵌的Tomcat是不需要用到的。
<!--部署成war包时开启【同时支持war和jar启动部署】↓↓↓↓-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<scope>provided</scope>
</dependency>
<!--部署成war包时开启【同时支持war和jar启动部署】↑↑↑↑-->
这种方式的好处是,打包的war包同时适合java -jar命令启动以及部署到外部容器中。
3、由jar变成war
<packaging>war</packaging>
4、注意的问题
4.1、项目名称和打包名称的一致性
使用外部Tomcat部署访问的时候,application.properties(或者application.yml)中配置的server.port和server.servlet.context-path将失效。
将使用tomcat的端口,tomcat,webapps下项目名进行访问。为了防止应用上下文所导致的项目访问资源加载不到的问题,建议pom.xml文件中<build></build>标签下添加<finalName></finalName>标签:
<build>
<!-- 应与application.properties(或application.yml)中context-path保持一致 -->
<finalName>war包名称</finalName>
</build>
此时打成的包的名称应该和application.properties的
server.port=8081
server.servlet.context-path=/war-demo
注意SpringBooot2.x,这里的写法为 server.servlet.context-path=
保持一致
<build>
<finalName>war-demo</finalName>
</build>
4.3、Error assembling WAR: web.xml attribute is required
Failed to execute goal org.apache.maven.plugins:maven-war-plugin:2.2:war (default-war)
on project XXX: Error assembling WAR: web.xml attribute is required (or pre-existing WEB-INF/web.xml if executing in update mode)
这个提示并不是你缺少依赖,而是在打包的时候,没有web.xml文件,因为SpringCloud 微服务多模块下没有web.xml文件,此时也不需要加入,在pom文件下加入一行代码如下:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>3.0.0</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
<warName>${project.artifactId}</warName>
</configuration>
</plugin>
此时不需要使用jar包的打包了。
<!-- <plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.1.1.RELEASE</version>
<configuration>
<fork>true</fork> 如果没有该配置,devtools不会生效
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin> -->