文章目录
- 代码配置类问题
- 1. 重复的Context Listener/多余的web.xml
- 1.1 原因
- 1.2 解决方案
- 2. SpringBoot的内置Tomcat没有去掉
- 2.1 原因
- 2.2 解决方案
- 3. 代码中有两个类继承了SpringApplication
- 3.1 原因
- 3.2 解决方案
- 4. Tomcat的server.xml中的配置问题
- 4.1 原因
- 4.2 解决方案
- 5. 多个Spring Boot启动器
- 5.1 原因
- 5.2 解决方案
- 本地配置问题
- 6. Maven插件配置问题
- 6.1 原因
- 6.2 解决方案
- 7. Deployment下有一个war, 一个war exploded
- 7.1 原因
- 7.2 解决方案
最近接手运维一个旧项目,遇到了项目一直起不来的问题,检查日志发现应用竟然启动了两次导致了一些端口冲突,本文就springboot在tomcat中启动两次的问题提供一些可能的原因和处理方案
代码配置类问题
1. 重复的Context Listener/多余的web.xml
1.1 原因
在早期的Servlet和JSP应用程序中,web.xml
文件是必须的,它用于配置Servlet、过滤器、监听器等。然而,从Servlet 3.0开始,引入了注解(如@WebServlet、@WebFilter、@WebListener等),使得开发者可以不再需要web.xml
文件。
对于Spring Boot应用程序,它默认使用嵌入式的Servlet容器(如Tomcat),并且自动配置了大部分的设置。因此,web.xml
文件通常是不需要的。
然而,如果你的Spring Boot应用程序仍然包含web.xml
文件,那么可能会导致应用程序启动两次。这是因为Spring Boot会自动注册一个ContextLoaderListener
,而web.xml
文件中可能也注册了一个。这样,就会有两个ContextLoaderListener
,导致应用程序启动两次。
<!-- web.xml -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
// Spring Boot主类
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
SpringApplication application = new SpringApplication(MyApplication.class);
application.addListeners(new ContextLoaderListener());
application.run(args);
}
}
1.2 解决方案
解决这个问题的方法是去掉web.xml
文件。如果你的应用程序需要一些特定的配置,你可以使用Spring Boot的各种特性来实现,如添加自定义的Servlet、过滤器、监听器等,总的来说,确保你的应用中只有一个Context Listener
,可以避免你的应用程序启动两次的问题。
2. SpringBoot的内置Tomcat没有去掉
2.1 原因
Spring Boot默认会自动配置并启动一个内嵌的Tomcat服务器,这使得开发者可以很方便地进行开发和测试,无需自行配置和管理一个独立的Tomcat服务器。然而,当你的Spring Boot应用程序需要部署到一个独立的Tomcat服务器上时,这就可能会导致问题。
如果你没有正确地配置你的Spring Boot应用程序,那么当你的应用程序启动时,可能会同时启动两个Tomcat服务器:一个是Spring Boot内嵌的Tomcat服务器,另一个是你的独立Tomcat服务器。这就是为什么你的应用程序会启动两次的原因。
2.2 解决方案
解决这个问题的方法是在你的Spring Boot应用程序中排除内嵌的Tomcat服务器。
在你的Spring Boot应用程序的pom.xml
或build.gradle
文件中,你需要找到spring-boot-starter-web
依赖。这个依赖默认会包含一个内嵌的Tomcat服务器。
你需要修改这个依赖,排除内嵌的Tomcat服务器。在pom.xml
文件中:
<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>
在build.gradle
文件中:
dependencies {
implementation('org.springframework.boot:spring-boot-starter-web') {
exclude group: 'org.springframework.boot', module: 'spring-boot-starter-tomcat'
}
}
3. 代码中有两个类继承了SpringApplication
3.1 原因
在一个Spring Boot应用程序中,通常会有一个主类继承了SpringApplication
或者调用了SpringApplication.run()
方法,这个类被称为主类或启动类,它是Spring Boot应用程序的入口点。当你启动你的Spring Boot应用程序时,Spring Boot会运行这个主类,初始化Spring应用上下文,然后启动内嵌的Tomcat服务器(如果有的话)。
如果你的代码中有两个类都继承了SpringApplication
或者都调用了SpringApplication.run()
方法,那么当你启动你的应用程序时,这两个类可能都会被运行,导致你的应用程序启动两次。
3.2 解决方案
解决这个问题的方法是确保你的代码中只有一个类继承了SpringApplication
或者调用了SpringApplication.run()
方法。
4. Tomcat的server.xml中的配置问题
4.1 原因
Tomcat的server.xml
文件是Tomcat服务器的主要配置文件,它包含了一些关于服务器的重要配置。如果在这个文件中的配置不正确,可能会导致应用程序启动两次。
一个常见的问题是,在server.xml
文件中配置了两个或更多的<Host>
元素。每个<Host>
元素代表一个虚拟主机,在Tomcat启动时,每个虚拟主机都会尝试启动部署在其上的应用程序。因此,如果你在server.xml
文件中配置了两个<Host>
元素,并且它们都部署了同一个应用程序,那么这个应用程序会启动两次。
4.2 解决方案
解决这个问题的方法是检查你的server.xml
文件,确保只有一个<Host>
元素部署了你的应用程序。
5. 多个Spring Boot启动器
5.1 原因
Spring Boot启动器(starters)是一种便捷的方式,可以将一组相关的依赖添加到你的项目中。例如,spring-boot-starter-web
就是一个常用的启动器,它包含了构建web应用程序所需要的所有基本依赖。
然而,如果你的项目中包含了多个启动器,尤其是那些有相互冲突的启动器,就可能会导致问题。例如,spring-boot-starter-web
和spring-boot-starter-webflux
都是用于构建web应用程序的启动器,但它们使用的是不同的技术栈(Servlet和Reactive),在同一个项目中同时使用这两个启动器可能会导致应用程序行为的不确定性,甚至可能导致应用程序启动两次。
5.2 解决方案
解决这个问题的方法是仔细审查你的项目依赖,确保没有添加冲突的启动器。
首先,你需要检查你的pom.xml
或build.gradle
文件,找出所有的Spring Boot启动器。
然后,你需要理解每个启动器的功能,并确定你的项目是否真的需要这个启动器。如果你的项目中包含了冲突的启动器,你需要选择其中一个,并移除其他的。
例如,如果你的项目中同时包含了spring-boot-starter-web
和spring-boot-starter-webflux
,你需要根据你的应用程序的需求选择其中一个。如果你的应用程序是基于Servlet的,你应该保留spring-boot-starter-web
并移除spring-boot-starter-webflux
。反之亦然。
本地配置问题
6. Maven插件配置问题
6.1 原因
Maven是一个强大的项目管理工具,它使用插件来执行各种任务。然而,如果你不正确配置Maven插件,可能会导致应用程序启动两次。
例如,你可能在pom.xml
文件中配置了spring-boot-maven-plugin
,并在<configuration>
部分设置了<fork>true</fork>
。这会导致Maven在一个新的进程中启动应用程序,然后在主进程中再次启动应用程序。
<!-- pom.xml -->
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<fork>true</fork> <!-- 这会导致应用程序启动两次 -->
</configuration>
</plugin>
</plugins>
</build>
6.2 解决方案
解决这个问题的方法是正确配置spring-boot-maven-plugin
。
首先,你需要检查你的pom.xml
文件,确保你没有设置<fork>true</fork>
。
然后,你需要将<fork>
设置为false
。这会导致Maven在同一个进程中启动应用程序,从而避免应用程序启动两次的问题。
<!-- pom.xml -->
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<fork>false</fork> <!-- 这会防止应用程序启动两次 -->
</configuration>
</plugin>
</plugins>
</build>
总的来说,正确配置spring-boot-maven-plugin
,可以避免你的应用程序启动两次的问题。
7. Deployment下有一个war, 一个war exploded
7.1 原因
在IntelliJ IDEA中,你可以选择将你的应用程序打包为war
文件或者war exploded
。war
文件是一个压缩的文件,包含了你的应用程序的所有代码和资源。而war exploded
是一个解压的版本,它包含了你的应用程序的所有代码和资源,但是它们是以文件和文件夹的形式存在的。
如果你在Deployment中同时配置了war
和war exploded
,那么当你启动你的应用程序时,IntelliJ IDEA会尝试启动两个应用程序。
7.2 解决方案
解决这个问题的方法是在Deployment中只配置一个war
或者war exploded
。