【SpringBoot】部署至Tomcat容器后启动完成后自动关闭的问题
背景首先说一下实践项目的形式:对外提供的API服务,无界面,无web.xml,打包方式:<packaging>war</packaging>问题说明项目打包后,部署至Tomcat的webapps目录下,启动Tomcat,发现启动成功后,打印日志(INFO级别,非ERROR):Unregistering JMX-exposed beans on
背景
首先说一下实践项目的形式:对外提供的API服务,无界面,无web.xml,打包方式:
<packaging>war</packaging>
问题说明
项目打包后,部署至Tomcat的webapps目录下,启动Tomcat,发现启动成功后,打印日志(INFO级别,非ERROR):
Unregistering JMX-exposed beans on shutdown
查看Tomcat状态:
jps
发现Tomcat未运行。
解决方案
问题原因: Tomcat容器和内置Tomcat冲突,即jar包冲突。
查看jar包:
cd tomcat/webapps
find . -name *tomcat*
发现有依赖jar包:
tomcat-embed-core-8.5.29.jar
tomcat-annotations-api.jar
tomcat-embed-el-8.5.29.jar
tomcat-jdbc-8.5.29.jar
tomcat-juli-8.5.29.jar
通过eclipse的Dependency Hierarchy
,搜索tomcat关键字,发现前三个jar包属于spring-boot-starter-tomcat
,后面俩依赖属于tomcat-jdbc
。
解决如下:
<!--部署成war包时开启↓↓↓↓-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-jdbc</artifactId>
<scope>provided</scope>
</dependency>
<!--部署成war包时开启↑↑↑↑-->
Maven的Scope简介
maven
中scope
依赖范围的概念:
依赖范围就是用来控制依赖和三种classpath
(编译classpath
,测试classpath
、运行classpath
)的关系,Maven
有如下几种依赖范围:
compile
: 编译依赖范围。如果没有指定,就会默认使用该依赖范围。使用此依赖范围的Maven依赖,对于编译、测试、运行三种classpath都有效。典型的例子是spring-code
,在编译、测试和运行的时候都需要使用该依赖。
test
: 测试依赖范围。使用次依赖范围的Maven依赖,只对于测试classpath有效,在编译主代码或者运行项目的使用时将无法使用此依赖。典型的例子是Jnuit
,它只有在编译测试代码及运行测试的时候才需要。
provided
:已提供依赖范围。使用此依赖范围的Maven依赖,对于编译和测试classpath有效,但在运行时候无效。典型的例子是servlet-api,编译和测试项目的时候需要该依赖,但在运行项目的时候,由于容器以及提供,就不需要Maven重复地引入一遍。
问题详解
在开发和测试过程中,使用的都是内置tomcat容器(存在于spring-boot-starter-web
),但是部署到Tomcat容器中,就会出现冲突报错。
1) 继承SpringBootServletInitializer,修改应用启动方式:
外部容器部署的话,就不能依赖于Application的main函数了,而是要以类似于web.xml文件配置的方式来启动Spring应用上下文,此时我们需要在启动类中继承SpringBootServletInitializer并实现configure方法
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.support.SpringBootServletInitializer;
@SpringBootApplication
public class WebApplication extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(WebApplication.class);
}
public static void main(String[] args) {
SpringApplication.run(WebApplication.class, args);
}
}
这个类的作用与在web.xml中配置负责初始化Spring应用上下文的监听器作用类似,只不过在这里不需要编写额外的XML文件了。
2)移除对嵌入式Tomcat的依赖
<!--部署成war包时开启↓↓↓↓-->
<!--添加servlet-api的依赖-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-jdbc</artifactId>
<scope>provided</scope>
</dependency>
<!--部署成war包时开启↑↑↑↑-->
3)打包方式
<packaging>war</packaging>
4)修改编译设置
方法一:
<build>
<plugins>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>2.6</version>
<configuration>
<!--如果想在没有web.xml文件的情况下构建WAR,请设置为false。-->
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
</plugins>
</build>
方法二:版本3.0.0的插件 web.xml不存在问题,所以可以通过升级插件来解决问题
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>3.0.0</version>
</plugin>
5)上下文路径
打成的包的名称应该和application.yml
的
server.context-path=/api
保持一致
<build>
<finalName>test</finalName>
</build>
如果不一样发布到tomcat的webapps下上下文会变化
如果想了解SpringBoot是如何帮我们省去web.xml的话,可以查看文章:
https://www.jianshu.com/p/3c94d7e76998?utm_source=oschina-app
更多推荐
所有评论(0)