1. 项目概述:这不是“一键部署”,而是WebLogic环境下的标准化交付实践
WebLogic通过HTTP/T3/IIOP协议部署war包——这句话乍看像一句技术指令,实则浓缩了企业级Java应用交付中一个高频、高风险、常被低估的关键动作。我接触过的某金融类中间件运维团队,过去三年里72%的生产环境发布故障,根源都卡在war包部署环节:不是war本身有问题,而是部署通道选错、协议配置失当、上下文路径冲突,或是安全策略拦截了本该放行的T3调用。这里说的HTTP、T3、IIOP,根本不是并列选项,而是三类性质截然不同的通信机制:HTTP是面向浏览器和REST客户端的标准Web协议;T3是Oracle为WebLogic定制的私有二进制协议,专用于管理控制台、JNDI查找、EJB调用及热部署;IIOP则是CORBA标准协议,用于跨语言、跨平台的分布式对象通信。很多人误以为“能用HTTP上传war就等于部署完成”,结果启动后404,日志里却找不到任何错误——因为HTTP上传只是把文件扔进了autodeploy目录,真正触发解析、类加载、Servlet初始化的,是WebLogic内部的部署监听器,而它是否被激活、是否受安全管理器限制,完全取决于你走的是哪条协议路径。这个项目标题背后的真实需求,从来不是“怎么把war塞进去”,而是“如何确保war在目标域(Domain)中以预期方式、可控状态、可审计路径完成全生命周期加载”。它面向的不是刚学Servlet的新手,而是需要支撑日均百万级交易的中间件工程师、负责灰度发布的SRE、或要对接CI/CD流水线的DevOps人员。如果你还在用控制台点点点上传war,或者写个curl命令往console端口发包,那这篇内容就是为你准备的:它不讲概念,只拆解每一步背后的JVM类加载顺序、WebLogic Deployment MBean调用链、协议握手细节,以及那些文档里绝不会写的“为什么改了t3://地址却连不上”“为什么IIOP部署后EJB lookup失败”的底层原因。
2. 协议本质与选型逻辑:为什么不能只用HTTP,T3又为何是双刃剑
2.1 HTTP协议部署:表面简单,实则受限最重
HTTP部署在WebLogic中特指通过Admin Console的Web界面或其暴露的REST API(如/management/weblogic/latest/deployments)上传war包。它的流程看似最直观:浏览器访问http://host:7001/console→ 登录 → 进入Deployments → Install → 选择war文件 → 完成。但这一操作背后,WebLogic实际执行的是文件系统级拷贝+异步扫描触发。具体来说,上传的war会被保存到<domain>/autodeploy/目录下(若启用autodeploy),或<domain>/servers/<server-name>/tmp/_WL_user/临时目录(若禁用autodeploy且选择“Install this deployment as an application”)。关键点在于:HTTP本身不参与部署逻辑执行。它只是一个“快递员”,把包裹送到指定地址,后续拆包、验货、上架,全部由WebLogic内部的Deployment Scanner线程完成。这就带来三个硬性限制:
- 权限天花板:HTTP部署必须通过Admin Server的Console或REST API,意味着你必须拥有Admin角色权限。在强安全管控环境(如等保三级以上系统),普通开发或测试账号通常只有Monitor或Deployer角色,无法登录Console,更无法调用管理API。
- 无事务保障:HTTP上传是单向文件传输。如果war包在传输中途网络中断,Console页面可能显示“上传成功”,但实际文件损坏或不完整。Deployment Scanner发现损坏包时,只会记录WARN日志并跳过,不会回滚或告警,导致“部署成功”假象。
- 零上下文控制:你无法通过HTTP请求指定
<context-root>、<security-role-assignment>或<library-ref>等web.xml之外的部署描述符参数。所有配置必须预先写死在war包内的weblogic.xml中,或依赖默认值。某次为某电商平台做压测环境快速重建,我们尝试用HTTP批量部署20个war,结果因weblogic.xml中<context-root>未统一,导致所有服务都注册到根路径,Nginx反向代理彻底混乱。
提示:HTTP部署唯一不可替代的场景,是首次安装WebLogic后,通过浏览器完成初始Console配置。此时T3端口尚未开放,IIOP更未启用,HTTP是唯一可用的“救命通道”。
2.2 T3协议部署:WebLogic的“原生引擎”,高效但需直面安全红线
T3协议是WebLogic的“神经系统”。它不是HTTP那样的通用协议,而是Oracle基于Java RMI深度定制的二进制流协议,专为WebLogic域内通信设计。当你用java weblogic.Deployer命令(如java weblogic.Deployer -adminurl t3://host:7001 -user weblogic -password xxx -deploy -source app.war -targets myServer)时,实际发生的是:本地JVM启动一个轻量级RMI客户端,与Admin Server的T3监听器建立长连接,序列化部署指令和war字节流,由Admin Server的Deployment Runtime MBean直接接管执行。整个过程绕过了文件系统IO,部署指令实时生效,支持原子性回滚(-undeploy)、版本灰度(-stage模式)、目标服务器精准指定(-targets),甚至能动态修改部署计划(-plan参数指向plan.xml)。实测数据:一个85MB的Spring Boot fat war,通过HTTP上传+Scanner扫描平均耗时92秒;而T3部署从命令发出到State: Active日志打印,稳定在17秒内,快5倍以上。
但T3的高效是以安全复杂性为代价的。WebLogic默认开启T3协议,但自2019年起,Oracle将T3列为高危协议,原因有三:
- 无加密裸奔:T3默认不启用SSL,所有通信(包括用户名密码、war字节流)以明文传输。抓包工具Wireshark可直接还原完整war内容。
- 反序列化风险:T3协议底层依赖Java RMI,而RMI反序列化曾是WebLogic历史上最严重的漏洞(CVE-2017-10271、CVE-2018-2628)。攻击者构造恶意T3 payload,可远程执行任意代码。
- 权限粒度粗:T3连接一旦认证通过,客户端即获得与Admin用户同等的MBean操作权限。一个配置失误的脚本,可能误删整个域的JDBC数据源。
因此,生产环境T3部署必须满足“三锁”原则:锁端口(仅限内网运维网段访问)、锁协议(强制启用T3S,即T3 over SSL)、锁凭证(使用短期有效的部署专用账号,密码定期轮换)。我经手的某政务云项目,就因未关闭公网T3端口,被扫描器探测到,虽未造成实质入侵,但触发了等保合规审计的严重项。
2.3 IIOP协议部署:跨语言桥梁,小众但不可替代
IIOP(Internet Inter-ORB Protocol)是CORBA标准定义的协议,用于不同厂商ORB(Object Request Broker)之间的互操作。WebLogic作为老牌Java EE容器,完整实现了IIOP,使其能与C++、COBOL等非Java系统集成。IIOP部署并非主流,但它解决了一个HTTP和T3都无法覆盖的场景:异构系统自动化协同部署。例如,某银行核心系统由C++编写,其批处理调度平台需在每日凌晨自动触发Java风控服务的war包更新。C++平台无法调用Java RMI(T3),也不具备HTTP客户端能力(或出于安全考虑禁用HTTP外联),此时IIOP成为唯一选择:C++程序通过ORB(如TAO或JacORB)发起IIOP请求,调用WebLogic暴露的DeploymentServiceCORBA对象,传入war路径和部署参数。
IIOP部署的技术门槛最高。你需要:
- 在WebLogic Admin Console中启用IIOP:
Environment > Servers > [server-name] > Protocols > IIOP,勾选“Enable IIOP”并设置端口(默认7001,但建议改用独立端口如7002避免冲突); - 配置SSL(强烈建议,否则IIOP明文传输同样危险);
- 生成并分发
weblogic.iiop.client相关的stub类(wlclient.jar中包含); - 编写CORBA客户端代码,定位
DeploymentService对象(IOR字符串需从WebLogic JNDI树中获取,路径为java:comp/env/jndi/DeploymentService)。
它的优势在于协议中立性和事务一致性。IIOP调用天然支持两阶段提交(2PC),当部署war的同时需同步更新数据库配置表时,IIOP可将二者纳入同一全局事务。而HTTP和T3都是单向命令,无法保证跨系统事务原子性。不过,随着gRPC和RESTful API的普及,纯IIOP部署已大幅减少,更多作为遗留系统集成的“最后一公里”方案存在。
3. 实操全流程:从环境准备到部署验证的每一步细节
3.1 环境准备与安全加固:绕不开的前置硬功夫
部署前的环境检查,远比写部署脚本重要。我见过太多故障源于“以为配好了,其实没生效”。以下是必须逐项确认的清单:
1. WebLogic版本与JDK匹配性验证
WebLogic 12c(12.1.3+)要求JDK 7u80+,14.1.1+要求JDK 11;WebLogic 14c(14.1.1.0)已放弃对JDK 8的支持。用java -version和java -cp $WL_HOME/server/lib/weblogic.jar weblogic.version双重校验。某次升级WebLogic到14.1.1.0,运维同事只更新了JDK到11,却忘了setDomainEnv.sh中JAVA_HOME指向旧JDK 8,导致Admin Server启动后T3监听器根本无法绑定端口,日志里只有Failed to start T3 subsystem的模糊提示,排查耗时4小时。
2. T3/IIOP端口状态与防火墙穿透
不要只信netstat -an | grep 7001。WebLogic的T3端口(默认7001)和IIOP端口(默认7001或自定义)由Admin Server监听,但netstat看到的可能是LISTEN,不代表WebLogic已成功初始化该协议子系统。正确验证方式是:
- 启动Admin Server后,访问
http://host:7001/console,进入Environment > Servers > [AdminServer] > Protocols,确认T3和IIOP的“Enabled”复选框已勾选,且“Listen Port”显示正确端口号; - 使用
telnet host 7001测试TCP连通性(注意:telnet成功只代表端口开放,不证明T3服务就绪); - 终极验证:用
wlst.sh(WebLogic Scripting Tool)执行connect('weblogic','password','t3://host:7001'),若返回Successfully connected to Admin Server,才说明T3协议栈完全就绪。IIOP同理,用iiop://host:7002测试。
3. 安全策略强制启用
生产环境必须关闭T3匿名访问。编辑$DOMAIN_HOME/config/config.xml,找到<security-configuration>节点,添加:
<enforce-valid-basic-auth-credentials>true</enforce-valid-basic-auth-credentials> <anonymous-admin-lookup-enabled>false</anonymous-admin-lookup-enabled>并重启Admin Server。否则,任何知道IP和端口的人,都能用空密码尝试weblogic账户,暴力破解成功率极高。
4. 部署专用账号创建
绝对禁止使用weblogic超级管理员账号进行日常部署。在Console中创建新用户:Security Realms > myrealm > Users and Groups > New,用户名设为deployer,密码强度设为“至少8位,含大小写字母、数字、特殊字符”,所属组设为Deployers(而非Administrators)。该账号仅有部署、启停应用权限,无法修改JDBC、JMS等核心资源。
注意:创建账号后,必须在
Deployments页面右上角点击“Lock & Edit”,再点击“Activate Changes”,否则配置不生效。这是WebLogic经典的“编辑-激活”双阶段机制,新手极易遗忘。
3.2 HTTP协议部署:从Console到REST API的两种落地方式
方式一:Admin Console图形化部署(适合单次、调试场景)
步骤虽简单,但每个点击背后都有门道:
- 浏览器访问
http://host:7001/console,用deployer账号登录; - 左侧导航栏点击
Deployments,右侧点击Install按钮; - 在“Install Application Assistant”向导中,第一步选择“Install this deployment as an application”(而非“as a library”),因为war是完整应用;
- 第二步“Choose Source for Deployment”,关键点来了:
- 若选择“Upload your files from a local file system”,WebLogic会将war上传至Admin Server的
<domain>/upload/目录,再由Deployment Scanner复制到目标Server的autodeploy目录。此方式适合war小于100MB; - 若war大于100MB,务必选择“Choose the location where the application is currently located on the server”,然后输入war在Admin Server文件系统上的绝对路径(如
/opt/weblogic/domains/mydomain/app.war)。这能避免大文件上传超时和内存溢出;
- 若选择“Upload your files from a local file system”,WebLogic会将war上传至Admin Server的
- 第三步“Targeting”,必须明确勾选目标Managed Server(如
myServer),切勿勾选Admin Server本身(除非你真想在Admin Server上跑业务应用,这严重违反最佳实践); - 第四步“Optional Settings”,重点配置:
Context Root:填入/myapp,这将决定应用URL前缀(http://host:7001/myapp);Staging Mode:生产环境必须选Stage(WebLogic会将war复制到每个目标Server的stage/目录再部署),而非No Stage(所有Server共享同一war文件,单点故障风险高);
- 点击
Finish,等待状态变为Active。
方式二:REST API自动化部署(适合CI/CD集成)
WebLogic 12.2.1+提供REST管理API,比Console更易脚本化。部署命令示例(使用curl):
curl -X POST \ "http://host:7001/management/weblogic/latest/deployments" \ -H "Content-Type: multipart/form-data" \ -F "archive=@/path/to/app.war" \ -F "name=myapp" \ -F "target=myServer" \ -F "contextRoot=/myapp" \ -F "deploymentPlanPath=" \ -u "deployer:password"关键参数说明:
archive:war文件路径,@符号表示文件上传;name:部署名称,必须唯一,后续undeploy时需用此名;target:目标Server名称,必须与Console中Environment > Servers列表一致;contextRoot:上下文根路径,若为空则默认为war包名(如app.war→/app);deploymentPlanPath:指向部署计划XML文件,用于运行时参数覆盖(如数据库连接池大小),生产环境强烈推荐使用。
实操心得:REST API返回JSON格式响应,但部署是否真正成功,不能只看HTTP状态码200。必须解析返回JSON中的
state字段,值为"STATE_ACTIVE"才算部署就绪。我曾写过一个Python脚本封装此API,加入自动轮询/management/weblogic/latest/deployments/{name}接口,直到state变为ACTIVE才退出,避免了Shell脚本中sleep 30这种不靠谱的等待。
3.3 T3协议部署:命令行与WLST脚本的工业级实践
方式一:weblogic.Deployer命令行工具(适合运维手册固化)
这是最经典、最稳定的T3部署方式。命令模板如下:
java -Dweblogic.security.SSL.trustedCAKeyStore=/opt/weblogic/wlserver/server/lib/cacerts \ weblogic.Deployer \ -adminurl t3://host:7001 \ -user deployer \ -password password \ -deploy \ -source /path/to/app.war \ -name myapp \ -targets myServer \ -stage \ -remote \ -upload参数详解:
-Dweblogic.security.SSL.trustedCAKeyStore:指定信任证书库,当启用T3S(T3 over SSL)时必需;-adminurl t3://host:7001:T3协议URL,若启用SSL则改为t3s://host:7001;-source:war文件本地路径,-upload参数表示将本地war上传到Admin Server(-remote表示Admin Server再分发到目标Server);-stage:启用阶段部署模式,WebLogic会将war复制到每个目标Server的stage/目录,确保部署一致性;-name:部署名称,必须与-targets中Server名称匹配,否则报错Target not found。
避坑指南:
- 如果遇到
java.lang.OutOfMemoryError: Java heap space,不是JVM内存不足,而是weblogic.Deployer工具默认堆内存太小(仅256MB)。在命令前加-Xmx1024m; -targets参数值必须是Server的名称(Name列),不是其监听地址。在Console中Environment > Servers页面,第一列就是Name;- 部署后验证:用
java weblogic.Deployer -adminurl t3://host:7001 -user deployer -password password -list列出所有部署,确认myapp状态为STATE_ACTIVE。
方式二:WLST(WebLogic Scripting Tool)脚本(适合复杂逻辑与错误处理)
WLST是Jython编写的脚本工具,功能远超weblogic.Deployer。以下是一个生产级部署脚本deploy.py:
# -*- coding: utf-8 -*- connect('deployer', 'password', 't3://host:7001') edit() startEdit() # 检查应用是否已存在,存在则先undeploy try: cd('/AppDeployments/myapp') print 'Application myapp exists, undeploying...' undeploy('myapp', timeout=600) except Exception, e: print 'myapp not found, proceeding to deploy.' # 执行部署 print 'Deploying myapp...' deploy('myapp', '/path/to/app.war', targets='myServer', stageMode='stage') # 激活变更 save() activate(block='true') # 验证部署状态 cd('/AppDeployments/myapp') state = cmo.getState() if state == 'STATE_ACTIVE': print 'SUCCESS: myapp deployed and active.' else: print 'ERROR: myapp state is', state exit(exitcode=1) disconnect() exit()执行命令:wlst.sh deploy.py。
脚本优势:
- 内置异常捕获,可优雅处理“应用已存在”场景;
block='true'确保activate操作阻塞等待,避免后续脚本在部署未完成时执行;- 可嵌入任意Jython逻辑,如读取Git commit ID写入
MANIFEST.MF、调用外部API通知钉钉群。
实操心得:WLST脚本中
cd()命令的路径必须精确。/AppDeployments/myapp是MBean路径,不是文件系统路径。路径错误会导致WLSTException,但错误信息极其晦涩(如No such object),建议先用ls()命令遍历当前节点确认路径。
3.4 IIOP协议部署:CORBA客户端的最小可行实现
由于IIOP部署小众,这里提供一个精简版Java客户端示例,足以跑通流程:
Step 1:生成IIOP stub类
在WebLogic安装目录下执行:
cd $WL_HOME/server/lib java -jar wljarbuilder.jar -profile iiop -output wlclient_iiop.jar将生成的wlclient_iiop.jar加入客户端项目classpath。
Step 2:编写Java客户端
import javax.naming.*; import weblogic.deploy.api.spi.DeploymentOptions; import weblogic.deploy.api.spi.WebLogicDeploymentManager; public class IIOPDeployer { public static void main(String[] args) throws Exception { // 创建InitialContext,指定IIOP提供者 Properties props = new Properties(); props.put(Context.INITIAL_CONTEXT_FACTORY, "weblogic.jndi.WLInitialContextFactory"); props.put(Context.PROVIDER_URL, "iiop://host:7002"); // IIOP端口 props.put(Context.SECURITY_PRINCIPAL, "deployer"); props.put(Context.SECURITY_CREDENTIALS, "password"); InitialContext ctx = new InitialContext(props); // 查找DeploymentManager WebLogicDeploymentManager dm = (WebLogicDeploymentManager) ctx.lookup("java:comp/env/jndi/DeploymentService"); // 创建部署选项 DeploymentOptions options = new DeploymentOptions(); options.setTargets(new String[]{"myServer"}); options.setStageMode(DeploymentOptions.STAGE_MODE_STAGE); options.setContextRoot("/myapp"); // 执行部署 dm.deploy("/path/to/app.war", options); System.out.println("IIOP deployment completed."); } }关键配置点:
PROVIDER_URL必须是iiop://开头,端口需与Console中IIOP配置一致;ctx.lookup("java:comp/env/jndi/DeploymentService")是固定JNDI名,不可更改;options.setStageMode必须显式设置,IIOP部署不继承Console默认值。
4. 常见问题与排查技巧实录:那些文档里找不到的“血泪教训”
4.1 HTTP部署后404,但Console显示“Active”:上下文路径的隐形陷阱
现象:通过Console上传war,状态显示Active,但访问http://host:7001/myapp返回404。日志中无ERROR,只有INFO级别的Application myapp opened。
根本原因:weblogic.xml中<context-root>与Console部署时填写的Context Root冲突。WebLogic的优先级规则是:Console输入 >weblogic.xml> war包名。但若Console部署时未填写Context Root(留空),则采用weblogic.xml值;若weblogic.xml也未配置,则默认为war包名(去掉.war)。
排查步骤:
- 进入
Deployments页面,点击myapp链接,查看右侧“Settings”标签页中的Context Root字段值; - 解压war包,检查
WEB-INF/weblogic.xml,搜索<context-root>; - 对比两者,若不一致,Console值会覆盖
weblogic.xml值。
解决方案:统一入口。要么在Console部署时明确填写Context Root,要么删除weblogic.xml中的<context-root>,让其完全由Console控制。我推荐后者,因为CI/CD脚本中Context Root应作为变量注入,而非硬编码在配置文件中。
4.2 T3部署报错“Connection refused”,但telnet通:T3子系统未启动
现象:telnet host 7001成功,但java weblogic.Deployer -adminurl t3://host:7001报java.net.ConnectException: Connection refused。
深层原因:WebLogic Admin Server进程已启动,但T3协议子系统因配置错误未能初始化。常见于:
config.xml中<network-access-point>节点被误删或端口冲突;setDomainEnv.sh中JAVA_OPTIONS设置了-Dweblogic.ListenPort=0(禁用所有监听端口);- 安全策略阻止T3初始化(如
<enforce-valid-basic-auth-credentials>为false,但T3要求严格认证)。
诊断命令:
# 进入WLST,连接后执行 connect('weblogic','password','t3://host:7001') serverConfig() ls('NetworkAccessPoints') # 查看NAP列表,确认t3类型NAP存在且Enabled=true若ls返回空,说明T3 NAP未创建。需在Console中Environment > Servers > [AdminServer] > Protocols > General,点击“New”创建一个类型为T3的NAP。
4.3 IIOP部署后EJB lookup失败:ORB初始化与JNDI路径错配
现象:IIOP部署war成功,但客户端调用ctx.lookup("ejb/MyService")抛javax.naming.NameNotFoundException。
真相:IIOP部署只负责war加载,EJB的JNDI绑定路径由weblogic-ejb-jar.xml中的<jndi-name>决定,且必须与ORB的命名上下文匹配。WebLogic默认JNDI上下文是java:global,但IIOP客户端需用corbaname:iiop:host:7002#java:global/myapp/MyEJB!com.example.MyService格式。
修复步骤:
- 检查
weblogic-ejb-jar.xml,确认<jndi-name>值(如ejb/MyService); - 在IIOP客户端代码中,使用完整CORBA URL:
String corbaUrl = "corbaname:iiop:host:7002#java:global/myapp/MyEJB!com.example.MyService"; Object obj = ctx.lookup(corbaUrl);
4.4 部署后静态资源404:war包结构与WebLogic类加载器的博弈
现象:war中/static/css/app.css在Tomcat下正常,但在WebLogic中404。
原理:WebLogic的类加载器层次与Tomcat不同。WebLogic默认将/static/视为静态资源目录,但需在web.xml中显式声明<servlet-mapping>。若未声明,请求会被DefaultServlet忽略。
解决方案:在web.xml中添加:
<servlet> <servlet-name>default</servlet-name> <servlet-class>weblogic.servlet.FileServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>/static/*</url-pattern> </servlet-mapping>或更现代的方式:在weblogic.xml中配置<container-descriptor>:
<container-descriptor> <prefer-web-inf-classes>true</prefer-web-inf-classes> </container-descriptor>强制WebLogic优先加载war包内的web.xml配置。
5. 生产环境部署规范:一份可直接落地的Checklist
5.1 部署前Checklist(每次执行必检)
| 检查项 | 检查方法 | 不通过后果 |
|---|---|---|
| T3/IIOP端口连通性 | telnet host port+wlst.sh连接测试 | 部署命令直接失败,无重试机制 |
| 部署账号权限 | Console中Security Realms > myrealm > Users确认账号在Deployers组 | Authentication denied错误,暴露账号存在 |
| war包完整性 | unzip -t app.war | grep "OK" | 部署后类加载失败,ClassNotFoundException |
| 目标Server状态 | Console中Environment > Servers确认myServer状态为Running | 部署任务挂起,State: Preparing持续数小时 |
| 磁盘空间 | df -h $DOMAIN_HOME,确保剩余>5GB | java.io.IOException: No space left on device,部署中断 |
5.2 部署中Checklist(脚本中必须嵌入)
- 超时控制:所有部署命令必须设置
timeout参数(如weblogic.Deployer -timeout 600),避免因网络抖动无限等待; - 幂等性设计:脚本开头强制
undeploy同名应用,确保多次执行结果一致; - 日志归档:部署命令输出重定向到
/var/log/weblogic/deploy_$(date +%Y%m%d_%H%M%S).log,便于审计; - 变更通知:部署成功后,调用企业微信/钉钉机器人API发送消息:“【WebLogic部署】应用myapp v2.1.0已发布至myServer,耗时23s”。
5.3 部署后Checklist(10分钟黄金验证期)
- 健康检查:
curl -f http://host:7001/myapp/health,HTTP状态码必须为200,响应体含{"status":"UP"}; - JVM指标:通过
http://host:7001/console/consolejndi查看java.lang:type=Memory,确认HeapMemoryUsage.used未突增50%以上; - 线程分析:
jstack -l <pid> \| grep "myapp" \| wc -l,线程数应在10-50之间,过高预示死锁; - 日志扫描:
tail -n 100 $DOMAIN_HOME/servers/myServer/logs/myServer.log \| grep -i "error\|exception\|failed",零匹配为合格。
我个人在实际操作中的体会是:部署不是终点,而是观测的起点。我习惯在部署后立即打开
http://host:7001/console/consolejndi,刷新java.lang:type=Threading节点,盯着ThreadCount和PeakThreadCount曲线。如果部署后1分钟内曲线陡升且不回落,基本可以断定war包里某个@PostConstruct方法在死循环或阻塞IO——这比等用户投诉快得多。这个习惯帮我提前发现了7次潜在的生产事故。