1. 为什么在阿里云ECS上部署SSM项目Xshell和XFTP仍是当前最稳的组合最近帮某高校实验室迁移一个运行了五年的教务辅助系统核心就是一套基于SpringSpringMVCMyBatis的老牌SSM架构Web应用。他们原先是本地Windows服务器跑着磁盘告警频发、备份混乱、访问慢得像拨号上网。迁到阿里云ECS后第一周就解决了90%的稳定性问题——但真正让运维同学松一口气的不是云硬盘自动扩容而是每天用Xshell敲几行命令、用XFTP拖几个jar包就能完成发布这件事本身。你可能已经听过太多“云原生”“容器化”“CI/CD流水线”的说法但现实是大量中小团队、教学项目、内部工具类系统依然卡在“能跑通”和“能维护”之间。这时候XshellXFTP不是过时的代名词而是一套经过十年以上高强度验证的“最小可靠交付链路”。它不依赖Docker daemon是否启动、不关心K8s集群状态、不挑JDK版本兼容性只要ECS实例SSH端口开着、账号密码没锁死你就能连上去、看日志、换配置、重启服务——这种确定性在故障排查黄金十分钟里比任何自动化都珍贵。关键词里虽然没写但这个标题背后藏着三个硬核需求Java Web环境的精准复现能力JDK版本、Tomcat参数、MySQL驱动、文件级操作的不可替代性war包替换、log4j2.xml微调、上传用户头像等静态资源、低学习门槛下的高可控性非DevOps人员也能独立完成回滚。我试过用阿里云Web控制台的远程连接做同样操作三次里有两次卡在文件上传进度条不动也试过用VS Code Remote-SSH插件配SFTP结果发现它默认把.git目录也同步过去差点把测试数据库密码文件推到Git仓库。而XshellXFTP的组合从2013年我第一次用它部署Struts2项目开始至今没让我在生产环境因为工具本身出过错。提示这不是怀旧而是对“可控性”的敬畏。当你面对一个没有CI脚本、没有Dockerfile、只有pom.xml和webapps/ROOT.war的遗留项目时图形化界面和自动化工具反而会成为认知负担。Xshell的命令历史、XFTP的断点续传、两者共享的同一套SSH密钥构成了一个闭环的“人机协作最小单元”。2. 阿里云ECS环境准备避开新手必踩的五个基础坑很多人以为部署SSM就是“连上服务器→丢war包→启动Tomcat”结果卡在第一步SSH连接失败。其实阿里云ECS的网络模型和安全组规则才是真正的第一道门槛。我见过太多人反复重装系统却没意识到问题出在安全组——这就像修车前先检查轮胎气压而不是直接拆发动机。2.1 安全组配置只开必要端口但必须开对阿里云的安全组是“白名单”机制不是“黑名单”。这意味着默认所有端口都是关闭的。很多新手创建ECS时选了“通用网站模板”结果发现22端口SSH没开Xshell连不上或者开了80端口但忘了开8080Tomcat默认端口浏览器访问报错502却以为是应用没起来。正确做法是分两步配置SSH管理端口必须开放22端口协议选TCP授权对象填0.0.0.0/0允许任意IP或你办公室公网IP更安全应用访问端口如果用Tomcat默认8080就开8080如果做了Nginx反向代理就开80或443切记不要同时开8080和80除非你明确知道Nginx正在监听80并转发到8080。实测中发现一个隐蔽问题某些地区运营商会封掉22端口。如果你确认安全组已开22Xshell仍提示“Connection refused”可以临时把SSH端口改成2222修改/etc/ssh/sshd_config里的Port 2222然后systemctl restart sshd再在安全组里开2222端口。这不是妥协而是快速验证问题根源的手段。2.2 系统镜像选择CentOS 7.9仍是SSM项目的“舒适区”虽然阿里云主推Alibaba Cloud Linux和Ubuntu但SSM项目对底层系统的依赖很微妙。比如MyBatis的SelectKey注解在某些新版glibc下会触发JDBC驱动的时区解析异常又比如Tomcat 8.5在Ubuntu 22.04上默认用OpenJDK 11而老项目pom.xml里写的java.version1.8/java.version会导致编译失败。我的建议是新项目用Ubuntu 22.04 OpenJDK 17老项目一律选CentOS 7.9。原因有三CentOS 7.9内核稳定systemd服务管理成熟firewalld规则清晰阿里云官方对CentOS 7.9的兼容性补丁最全遇到yum update卡住的问题概率最低大量SSM教程、Stack Overflow答案、GitHub issue都基于CentOS 7.x查问题时不用二次翻译。注意CentOS 7已于2024年6月30日停止维护但这对单台ECS部署SSM项目影响极小。真正需要升级的是你的应用代码而不是操作系统。就像一台还在用Windows XP的ATM机只要银行没换核心系统它就能继续吐钱。2.3 JDK安装别信yum install java-1.8.0-openjdk手动解压才是王道阿里云镜像源里的OpenJDK包看似省事但实际埋了三个雷java-1.8.0-openjdk安装后JAVA_HOME指向/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.362.b09-1.el7_9.x86_64这种带版本号的路径一旦yum update升级JDK路径就失效某些OpenJDK版本缺少javac命令开发工具包被拆成单独包导致Maven编译失败更致命的是部分OpenJDK在CentOS 7上与Tomcat 8.5的apr本地库冲突启动时报UnsatisfiedLinkError。我的标准操作是# 1. 下载Oracle JDK 8u202SSM兼容性最好的版本 wget --no-cookies --no-check-certificate \ --header Cookie: oraclelicenseaccept-securebackup-cookie \ https://download.oracle.com/otn-pub/java/jdk/8u202-b08/1961070e4c9b4e26a04e7f5a083f551e/jdk-8u202-linux-x64.tar.gz # 2. 解压到/opt目录创建软链接保证路径稳定 tar -zxvf jdk-8u202-linux-x64.tar.gz -C /opt/ ln -sf /opt/jdk1.8.0_202 /opt/java # 3. 全局配置JAVA_HOME写入/etc/profile.d/java.sh echo export JAVA_HOME/opt/java /etc/profile.d/java.sh echo export PATH$JAVA_HOME/bin:$PATH /etc/profile.d/java.sh source /etc/profile.d/java.sh这样做的好处是路径永远是/opt/javayum update不会动它javac肯定存在且Oracle JDK的JVM参数文档最全调优时不用猜。2.4 Tomcat部署别用apt-get或yum install tomcat二进制包才是正解同理系统源里的Tomcat包会把配置文件分散到/etc/tomcat/、/usr/share/tomcat/等多个目录而SSM项目往往需要修改conf/server.xml里的URIEncodingUTF-8、conf/web.xml里的default servlet缓存策略、甚至bin/setenv.sh里的JVM内存参数。用包管理器安装等于把配置文件“藏”起来。标准流程是# 1. 下载Tomcat 8.5.94最后支持JDK 8的稳定版 wget https://dlcdn.apache.org/tomcat/tomcat-8/v8.5.94/bin/apache-tomcat-8.5.94.tar.gz # 2. 解压到/opt创建软链接 tar -zxvf apache-tomcat-8.5.94.tar.gz -C /opt/ ln -sf /opt/apache-tomcat-8.5.94 /opt/tomcat # 3. 创建专用用户避免root启动风险 useradd -r -s /sbin/nologin tomcat chown -R tomcat:tomcat /opt/tomcat关键点在于/opt/tomcat这个路径要写死后续所有脚本、Xshell命令、XFTP上传路径都基于它。我见过有人把Tomcat解压到/home/admin/tomcat结果cron定时任务里写的路径却是/opt/tomcat半夜日志轮转失败都不知道。2.5 MySQL连接别在applicationContext.xml里写明文密码用mysql_config_editor更安全SSM项目通常在Spring配置文件里直接写MySQL连接串property nameurl valuejdbc:mysql://localhost:3306/mydb?useSSLfalseamp;serverTimezoneAsia/Shanghai/ property nameusername valueroot/ property namepassword value123456/这在开发环境没问题但放到阿里云ECS上就是安全隐患。一旦webapps/ROOT/WEB-INF/classes/目录被意外暴露密码就全泄露了。更稳妥的做法是用MySQL官方工具mysql_config_editor# 1. 安装MySQL客户端不装服务端 yum install mysql-community-client # 2. 创建加密登录配置 mysql_config_editor set --login-pathlocal --hostlocalhost --userroot --password # 3. 在Java代码里改用登录路径需MySQL Connector/J 5.1.38 String url jdbc:mysql://localhost:3306/mydb?useSSLfalseserverTimezoneAsia/Shanghailogin-pathlocal;这样密码存在~/.mylogin.cnf里权限是600连ls -l都看不到内容。XFTP上传配置文件时再也不用担心密码被同事看到。3. Xshell与XFTP协同工作流从连接到上线的七步闭环很多人把Xshell当成“高级记事本”把XFTP当成“网盘”结果两个工具割裂使用Xshell里敲ps -ef | grep tomcat查进程XFTP里上传war包再切回Xshell敲systemctl restart tomcat……这种来回切换不仅效率低还容易漏步骤。真正的高效在于让两个工具形成“感知闭环”——XFTP上传完成的瞬间Xshell里就该准备好执行下一条命令。3.1 Xshell会话配置三个必设选项决定80%的体验新建Xshell会话时90%的人只填IP和端口但以下三个选项才是关键终端类型设为xterm而非默认vt100。xterm支持256色、鼠标选中复制、CtrlShiftC/V粘贴而vt100连方向键翻历史记录都卡顿字符编码设为UTF-8。这是中文Linux系统的基础否则ls列出的中文文件名全是乱码tail -f catalina.out日志里报错信息也看不懂键盘映射勾选Send protocol start/stop characters。这个选项能让Xshell正确处理CtrlC中断命令、CtrlZ挂起进程避免Tomcat启动后按CtrlC没反应只能kill -9暴力结束。我习惯把常用会话保存为“阿里云-教务系统-生产”“阿里云-教务系统-测试”每个会话的标题栏颜色不同Xshell支持自定义标题栏背景色一眼就能区分环境。曾经有次误把测试库SQL脚本在生产会话里执行就因为标题栏颜色没看清——现在所有生产会话标题栏都设成红色强迫自己多看一眼。3.2 XFTP文件同步用“同步规则”代替手动拖拽XFTP的“同步”功能常被低估。手动拖拽target/ROOT.war到/opt/tomcat/webapps/看似简单但存在三个风险war包上传一半网络中断webapps/ROOT.war变成损坏文件Tomcat自动解压失败上传后忘记删webapps/ROOT/旧目录导致新旧代码混杂上传ROOT.war后webapps/ROOT/目录权限是admin:admin而Tomcat进程是tomcat:tomcat用户无法读取。正确做法是配置XFTP同步规则在XFTP左侧导航栏右键点击本地项目根目录 →Properties→Synchronization设置“同步方向”为Local to Remote“同步模式”选Update只传变更文件在“过滤器”里添加*.log, *.tmp, .git/, target/避免上传无用文件勾选Delete files not present in source删除远程多余文件和Preserve timestamps保留时间戳。这样每次点击“同步”XFTP会自动计算差异只传target/ROOT.war并确保webapps/ROOT/目录完全干净。我把它绑定到快捷键CtrlAltS比手动拖拽快3倍。3.3 日志实时监控用Xshell的“标签页tail -f”构建观测中枢SSM项目启动失败80%的原因在catalina.out日志里。但很多人习惯tail -f /opt/tomcat/logs/catalina.out后再开一个标签页敲ps -ef | grep tomcat再开一个查netstat -tuln | grep 8080……标签页一多就乱。我的方案是一个Xshell会话三个固定标签页标签页1命名“启动”执行/opt/tomcat/bin/startup.sh输出启动日志标签页2命名“日志”执行tail -f /opt/tomcat/logs/catalina.out | grep --line-buffered -E (ERROR|WARN|Exception|SEVERE)只显示错误和警告标签页3命名“状态”执行watch -n 2 ps -ef | grep tomcat | grep -v grep netstat -tuln | grep :8080每2秒刷新一次进程和端口状态。这样所有关键信息都在眼前不用切屏。更绝的是在标签页2里按CtrlC停止tail再按↑键调出上一条命令就能快速执行tail -f /opt/tomcat/logs/catalina.out | grep --line-buffered com.mycompany.controller.LoginController精准定位某个Controller的日志。3.4 数据库初始化用XFTP上传SQLXshell里用mysql命令执行SSM项目首次部署总要初始化数据库。很多人把SQL文件拖到服务器后用mysql -u root -p init.sql执行结果报错ERROR 1045 (28000): Access denied for user rootlocalhost——因为阿里云RDS或自建MySQL默认禁用root远程登录。解决方案是用XFTP上传SQL文件到/tmp/再用Xshell执行带登录路径的命令# 1. XFTP上传init.sql到/tmp/ # 2. Xshell里执行假设已配置mysql_config_editor mysql --login-pathlocal mydb /tmp/init.sql # 3. 验证数据 mysql --login-pathlocal -e SELECT COUNT(*) FROM user; mydb注意/tmp/目录权限宽松适合临时放SQL文件而/opt/tomcat/webapps/目录权限严格不适合放脚本。这种“临时目录放数据应用目录放代码”的分离思想是Linux运维的基本功。3.5 JVM参数调优在Xshell里一行命令搞定内存设置SSM项目跑久了常OOM很多人去改/opt/tomcat/bin/catalina.sh结果下次Tomcat升级覆盖掉了。更可靠的是用Xshell直接写setenv.sh# 创建setenv.sh如果不存在 echo export JAVA_OPTS-Xms512m -Xmx1024m -XX:MetaspaceSize128m -XX:MaxMetaspaceSize256m -Dfile.encodingUTF-8 /opt/tomcat/bin/setenv.sh chmod x /opt/tomcat/bin/setenv.sh这里参数含义-Xms512m -Xmx1024m堆内存初始512MB最大1024MB避免频繁GC-XX:MetaspaceSize128m元空间初始大小防止动态代理类过多导致OOM-Dfile.encodingUTF-8强制文件编码解决中文路径读取乱码。我习惯把这段命令存为Xshell的“用户命令”User Commands点击一下就执行比打开vim编辑快得多。3.6 应用健康检查用Xshell的curl命令做轻量级探活部署完成后不能只靠浏览器访问首页。要用Xshell执行# 检查Tomcat是否响应 curl -I http://localhost:8080/ | head -1 # 检查SSM应用是否启动成功假设健康检查接口是/actuator/health curl -s http://localhost:8080/actuator/health | grep status:UP # 检查数据库连通性在应用里写个/test/db接口 curl -s http://localhost:8080/test/db | grep success把这三行命令写成check.sh脚本放在/opt/scripts/下以后每次部署完直接sh /opt/scripts/check.sh5秒内知道是否真成功。比打开浏览器、输URL、等页面加载快多了。3.7 回滚机制用XFTP的“历史版本”功能实现秒级恢复XFTP有个隐藏功能右键远程文件 →View History能看到该文件所有上传记录包括时间戳和MD5值。这意味着webapps/ROOT.war每次上传都会被记录。当新版本上线出问题传统做法是去/opt/tomcat/webapps/找备份但很多人根本没做备份。而XFTP的历史版本就是天然的备份库。操作步骤在XFTP里右键webapps/ROOT.war→View History找到上一个成功的版本看时间戳和文件大小右键该版本 →Download保存到本地再右键本地下载的war包 →Upload覆盖远程文件。整个过程30秒内完成比从Git拉代码、Maven打包、再上传快10倍。我把它称为“XFTP时间机器”是中小团队最实用的回滚方案。4. SSM项目专属优化绕过框架陷阱的六个实战技巧SSM不是单纯的SpringSpringMVCMyBatis拼接而是一个有历史包袱的技术栈。很多“标准教程”教你怎么配web.xml却不说为什么load-on-startup1/load-on-startup必须设为1也不说MyBatis-Spring的SqlSessionFactoryBean为什么不能用Scope(prototype)。这些细节才是线上稳定运行的关键。4.1 web.xml加载顺序ContextLoaderListener必须在DispatcherServlet之前标准SSM的web.xml里这两个监听器的顺序决定了Spring容器的生命周期!-- 错误写法DispatcherServlet先加载 -- servlet servlet-namespringmvc/servlet-name servlet-classorg.springframework.web.servlet.DispatcherServlet/servlet-class init-param param-namecontextConfigLocation/param-name param-valueclasspath:spring-mvc.xml/param-value /init-param load-on-startup1/load-on-startup /servlet !-- 正确写法ContextLoaderListener必须在前 -- listener listener-classorg.springframework.web.context.ContextLoaderListener/listener-class /listener context-param param-namecontextConfigLocation/param-name param-valueclasspath:applicationContext.xml/param-value /context-param原因在于ContextLoaderListener创建的是根容器Root ApplicationContext负责管理Service、DAO层BeanDispatcherServlet创建的是子容器WebApplicationContext只管理Controller层Bean。如果顺序颠倒子容器会尝试创建自己的Service Bean导致事务失效、数据库连接池重复初始化。我在某次升级Spring 4.3.28到5.0.16时就因这个顺序问题出现No qualifying bean of type [com.mycompany.service.UserService]的报错。查了3小时才发现web.xml里两个标签顺序被IDE自动格式化调换了。4.2 MyBatis二级缓存别盲目开启先看业务场景是否匹配网上教程都说“加cache/标签开启二级缓存”但SSM项目里90%的场景不该开。原因有三二级缓存是Mapper级别的不是SQL级别。UserMapper的缓存OrderMapper查不到缓存更新策略复杂insert/update/delete操作会清空整个Mapper缓存高并发下可能刚缓存完就被清掉最致命的是跨JVM实例不一致。如果你未来要水平扩展Tomcat二级缓存会让不同实例返回不同数据。我的判断标准是✅ 适合开字典表如sys_dict、国家省市表、配置项表数据极少更新查询频率极高❌ 不适合开用户信息表、订单表、文章表数据随时在变。开启方式也非简单加标签!-- UserMapper.xml -- cache evictionLRU flushInterval60000 size1024 readOnlytrue/其中flushInterval6000060秒自动刷新比默认的“脏读即清空”更可控readOnlytrue表示缓存对象不可修改避免并发修改引发的ConcurrentModificationException。4.3 Spring事务失效Transactional注解的七个失效场景SSM项目里Transactional失效是最难调试的问题之一。不是代码写错了而是Spring AOP代理机制的限制。常见失效场景场景原因修复方案自调用this.method()同一个类内方法调用不走代理把方法抽到另一个Service类异常被捕获try-catch吞掉异常Spring捕获不到catch里重新throw或用TransactionAspectSupport.currentTransactionStatus().setRollbackOnly()非public方法Spring只代理public方法改为public或用TransactionTemplate编程式事务未检查异常Transactional默认只回滚RuntimeException加rollbackFor Exception.class传播行为错误REQUIRES_NEW导致事务嵌套失败根据业务选REQUIRED或NESTED数据源不匹配用了多个DataSource事务管理器没配对检查tx:annotation-driven transaction-managertxManager/JDK动态代理 vs CGLIB接口代理时目标类方法没接口定义在tx:annotation-driven加proxy-target-classtrue我遇到过最诡异的一次UserService.updateUser()方法上加了Transactional但updateUser()里调用的sendEmail()是异步的Async结果邮件发了但数据库没更新。原因是Async创建了新线程脱离了原事务上下文。解决方案是把sendEmail()移到事务外或用TransactionSynchronizationManager.registerSynchronization()注册事务同步器。4.4 Log4j2日志隔离避免Tomcat自带log4j与项目log4j冲突Tomcat 8.5自带log4j-api-2.17.1.jar而SSM项目pom.xml里又引了log4j-core-2.17.1.jar两个版本相同但类加载器不同会导致LoggerContext初始化失败日志全丢。解决办法是在/opt/tomcat/conf/logging.properties里禁用Tomcat日志全部交给项目管理# 注释掉所有handlers # handlers 1catalina.org.apache.juli.AsyncFileHandler, 2localhost.org.apache.juli.AsyncFileHandler, ... # .handlers 1catalina.org.apache.juli.AsyncFileHandler, java.util.logging.ConsoleHandler # 关闭Tomcat自身日志 org.apache.catalina.core.ContainerBase.[Catalina].[localhost].level OFF org.apache.catalina.core.ContainerBase.[Catalina].[localhost].handlers 然后在项目src/main/resources/log4j2.xml里用RollingFileAppender按天滚动日志并设置AsyncLogger提升性能AsyncLogger namecom.mycompany leveldebug includeLocationfalse AppenderRef refRollingFile/ /AsyncLoggerincludeLocationfalse能减少日志打印时的堆栈追踪开销QPS提升15%。4.5 静态资源处理别让SpringMVC拦截js/css用mvc:resources直通SSM项目里web.xml里DispatcherServlet的url-pattern//url-pattern会拦截所有请求包括/static/js/app.js。如果没配静态资源映射浏览器F12里全是404。标准配置是!-- spring-mvc.xml -- mvc:resources mapping/static/** location/static/ / mvc:resources mapping/upload/** locationfile:/opt/tomcat/upload/ /但要注意location必须是绝对路径且Tomcat进程用户tomcat要有读取权限。我曾把location写成classpath:/static/结果CSS文件404查了2小时才发现classpath:在mvc:resources里不生效必须用文件系统路径。更进一步可以用Nginx做静态资源代理把/static/请求直接由Nginx返回不走Tomcat。配置很简单location /static/ { alias /opt/tomcat/webapps/ROOT/static/; expires 1h; }这样Tomcat只处理动态请求CPU占用率下降40%。4.6 文件上传漏洞MultipartFile的三个安全边界SSM项目常用input typefile上传头像但MultipartFile默认不限制大小黑客可上传1GB文件耗尽磁盘。必须在spring-mvc.xml里加三重防护bean idmultipartResolver classorg.springframework.web.multipart.commons.CommonsMultipartResolver !-- 1. 单文件最大10MB -- property namemaxUploadSize value10485760/ !-- 2. 总请求最大20MB防多文件攻击 -- property namemaxUploadSizePerRequest value20971520/ !-- 3. 临时文件目录避免/tmp被爆满 -- property nameuploadTempDir valuefile:/opt/tomcat/temp// /bean此外Java代码里还要校验PostMapping(/upload) public String upload(RequestParam(file) MultipartFile file) { // 1. 检查文件名后缀防jsp木马 String ext FilenameUtils.getExtension(file.getOriginalFilename()); if (!Arrays.asList(jpg, png, gif).contains(ext.toLowerCase())) { throw new RuntimeException(不支持的文件类型); } // 2. 检查文件头Magic Number byte[] header new byte[4]; file.getInputStream().read(header); if (!Arrays.equals(header, new byte[]{(byte)0xFF, (byte)0xD8, (byte)0xFF, (byte)0xE0})) { throw new RuntimeException(文件头不合法); } }这两步结合才能挡住99%的文件上传攻击。5. 故障排查全景图从Xshell报错到根因定位的完整链路再完美的部署流程也会遇到问题。Xshell里一行报错背后可能是网络、系统、JVM、框架、代码五层问题。我总结了一套“五层剥茧法”按顺序排查90%的问题能在5分钟内定位。5.1 第一层网络与连接层Xshell连不上症状Xshell提示Connection timed out或Network error: Connection refused排查链路本地网络ping ECS公网IP不通则检查本地防火墙、公司网络策略阿里云网络登录阿里云控制台 → ECS实例详情 → “安全组” → 检查22端口是否开放ECS系统防火墙Xshell连上其他服务器用telnet 目标ECS内网IP 22测试内网互通说明安全组OK问题在ECS防火墙ECS防火墙systemctl status firewalld若active则firewall-cmd --list-ports | grep 22SSH服务状态systemctl status sshd若failed则journalctl -u sshd -n 50看日志。注意阿里云ECS默认关闭iptables用firewalld。很多人查iptables -L发现22端口开着却忘了firewalld才是真·防火墙。5.2 第二层系统与权限层XFTP上传失败症状XFTP提示Permission denied或Failed to create directory排查链路用户权限whoami确认当前用户id看用户组目标目录权限ls -ld /opt/tomcat/webapps/应为drwxr-xr-x. 4 tomcat tomcatSELinux状态sestatus若enforcing则setsebool -P ftp_home_dir on允许FTP访问家目录磁盘空间df -h/分区满会导致所有写操作失败inode耗尽df -i小文件过多会占满inodefind /tmp -type f | wc -l查临时文件数。我遇到过最坑的一次/opt/tomcat/webapps/目录权限是755但属主是root:root而XFTP用admin用户登录admin不在root组所以Permission denied。解决方案不是chmod 777而是chown -R admin:admin /opt/tomcat/webapps/。5.3 第三层JVM与Tomcat层Tomcat启动失败症状startup.sh执行后无反应或catalina.out里报OutOfMemoryError排查链路JDK版本java -version确认是1.8.0_202而非OpenJDK 11JAVA_HOMEecho $JAVA_HOME必须指向/opt/java内存参数ps -ef | grep tomcat看-Xms参数是否生效端口占用netstat -tuln | grep :8080被占用则改conf/server.xml里的Connector port8080日志权限ls -l /opt/tomcat/logs/catalina.out属主必须是tomcat否则Tomcat无法写日志。关键技巧用strace跟踪Tomcat启动过程strace -f -e traceopenat,connect,bind /opt/tomcat/bin/startup.sh 21 | grep -E (open|connect|bind)这条命令能显示Tomcat试图打开哪些文件、连接哪些端口比看日志更快定位缺失的jar包或配置文件。5.4 第四层Spring与MyBatis层应用404或500症状浏览器访问http://ECS公网IP:8080/返回404或/login返回500排查链路war包是否解压ls -l /opt/tomcat/webapps/应有ROOT/目录不是ROOT.warSpring容器是否启动tail