1. Payara 环境下 Spring Boot 重复启动问题概述
问题定义与表现
在 Payara 容器中部署 Spring Boot WAR 时,应用存在“重复启动”的现象,即相同应用上下文被初始化多次,导致日志出现两次“Started …”等信息。核心表现包括相同端口监听、重复的 ServletContext 初始化,以及资源竞争引发的异常。
本文聚焦于 Payara 环境下 Spring Boot 重复启动问题的排查与解决(实战指南),通过一系列排查步骤,帮助开发与运维快速定位原因并给出修复方案。重要证据来自 Payara server.log 与应用级日志中对同一应用上下文的多次创建记录。
2. 场景复现与定位要点
复现条件与日志特征
在 Payara 9/Payara 5 版本中,重复启动的典型日志特征是两次“Tomcat started”或两次“Started Application”输出。留意是否存在两份应用上下文的根名称相同的条目。
如果你使用的是 WAR 部署,Payara 的部署配置和应用的初始化顺序可能导致同一个应用在同一域中被多次加载。诊断要点包括查看域日志中对同一上下文的重复部署记录。
3. 可能原因与排查要点
打包与依赖配置检查
第一步确认打包类型为 WAR,且嵌入式 Tomcat 不会随应用一同启动。关键是将 spring-boot-starter-tomcat 设置为 provided,以避免在 Payara 容器中重复启动嵌入式容器。
此外,避免在同一个应用中同时存在两个 Spring Boot 启动点(例如多份主类或重复的 SpringApplication.run 调用)。
4. 实战排查与修复步骤
步骤A:修改打包与依赖配置
将 Maven/Gradle 配置调整为 WAR 包,并把嵌入式容器依赖设为 provided,确保 Payara 负责容器的启动与管理。核心变更如下所示。
<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-tomcat</artifactId><scope>provided</scope></dependency>
</dependencies>额外要点:确保打包为 WAR,并在主类中使用 SpringBootServletInitializer 以支持外部容器部署。
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;public class MyApp extends SpringBootServletInitializer {@Overrideprotected SpringApplicationBuilder configure(SpringApplicationBuilder application) {return application.sources(MyApp.class);}public static void main(String[] args) {SpringApplication.run(MyApp.class, args);}
}步骤B:检查并优化 Payara 部署配置
在 Payara 中,确保应用以部署的 WAR 形式运行,且不要在域配置中重复创建相同应用。关键点包括:域中的应用唯一性、部署站点单一、以及对同名应用的重复部署排除。

可通过 Payara Admin Console 检查已部署应用的上下文路径和应用名,确保没有重复的部署单元。诊断要点是域内日志中对同一上下文的多次部署记录。
# Payara 管理命令示例(你镜像中使用的命令可能不同)
asadmin list-apps
asadmin undeploy <应用名> -admindotlog
asadmin deploy <应用的war包路径>
步骤C:排查应用内部的重复启动点
后端代码中如果存在多处调用 SpringApplication.run,或存在重复的 ServletContextInitializer,都会引发重复上下文初始化。检查点是主启动类与派生类、以及任何继承 SpringBootServletInitializer 的实现。
一个常见的错误是把一个独立的 Spring Boot 应用也作为独立的 WAR 部署在同一域中,造成两个独立的应用上下文。解决方法是确保只有一个入口点,并且 WAR 部署不包含额外的独立引导。
@SpringBootApplication
public class MyApp {public static void main(String[] args) {// 仅写一次入口点SpringApplication.run(MyApp.class, args);}
}步骤D:验证调整后的行为
完成上述修改后,重启 Payara 域并重新部署 WAR,观察日志以确认是否只有一个应用上下文被初始化。验证要点是日志中没有重复的“Started”条目,且端口占用恢复正常。
也可通过简单的健康端点进行探测,例如在浏览器请求应用的健康路径,确保没有并发初始化的日志输出。
# 通过 curl 测试健康端点
curl -sS http://<域名>:<端口>/<应用上下文>/actuator/health


