Java EE 企业应用 E08:同一 WAR 在第二运行时能证明什么
原运行时 /api/health 正常,新运行时却找不到数据源
Open Liberty 的 server.xml 定义 jdbc/Procurement、PostgreSQL 驱动位置、主机端口、WAR 上下文根;迁移到第二个 Jakarta EE 运行时,把同一个 WAR 文件复制进去,不会自动复制服务器的资源定义。部署可能失败,也可能首次 getConnection() 才报错。即便健康端点返回 ready,它不查库、不验证认证或消息;不能把一张 HTTP 200 截图写成“采购审批系统已可移植”。E08 的先修是主线 00–39 的完整业务、权限、消息及交付验收;若先修不齐,应明确写未覆盖,而不是从早期 DataSource 探针外推全链等价。
第二运行时已选 Eclipse GlassFish 8.0.4。writing-plans/javaee-enterprise/VERSIONS.md 记录该版的厂商 EE 11/JDK 21+ 资料与公共 TCK 清单指向 8.0.0-M12 的区别:**不能声称 8.0.4 的 TCK 已由那个 M12 清单证明。**本机已经把原运行时构建的同一 WAR 部署到 GlassFish,完成健康、受管数据源与部分采购回环;这只构成应用移植的局部证据,不能替代 00–39 的消息、身份、权限及交付验收。兼容清单陈述的是某一产品版本在某一 profile/Java 组合下的规范符合性,E08 要检验的是同一个应用在两种真实配置下的行为;这两件事不能互换。
锁定“同一应用”的可比较范围
可移植性测的是业务接口和规范边界,而不要求厂商配置文件字节一致。两个运行时中应用代码仍引用 jdbc/Procurement,资源底层驱动路径和口令注入方式可不同;但若为了第二运行时顺利部署而把 @Resource 改成在代码里调用 DriverManager.getConnection(),就已经改变了被比较的应用责任。部署失败需先区分应用层类找不到、受管资源解析失败、数据库连接失败和真正的业务 SQL 冲突。每一层的正常与负例都保留独立证据,避免“把 500 修成 200”却实际连错库。
若应用依赖平台以外的私有 API,必须在清单里列出 import、配置及替代路径:只有同时属于目标 Platform 的标准契约,才可能要求两款完整实现具有对应行为;厂商的连接池诊断端点、部署插件和内部日志格式不是标准 API。即便相同规范,也可能有可配置的默认超时、连接验证或线程资源数量;这类差异需在安全容量约束下显式设置,不用“兼容”替代运行手册。主线的 JAVAEE_DEMO_MODE 是专用实验开关,GlassFish 若忽略环境变量或启动脚本未注入,出现 404 不代表 REST 规范不兼容;如果意外开启则反而有安全风险。
首先记录基线 WAR 的 SHA-256、Maven/插件/Java 21 版本、配置文件与数据库 schema 版本。如果源代码、JDBC 驱动、消息 provider、安全存储与数据库数据集在移动过程中一起改变,新环境通过一次下单也不知是哪项差异造成。优先使用字节完全相同的 WAR;若第二运行时需要等价构建以处理应用打包差异,分别记录两个构建的提交、依赖树、WAR 差异和为什么不可直接复用。不能把“同源代码重新编译且换了 jar”简写成“相同 WAR 运行通过”。两个运行时使用隔离库和合成身份,执行相同 schema 迁移及可追溯种子数据,不允许同时写同一个 javaee_lab 后根据混合行集合判断移植成功。
| 项目 | Open Liberty 26.0.0.5 现有入口 | 第二运行时待提供的等价项 |
|---|---|---|
| 平台功能 | jakartaee-11.0 与 jdbc-4.3 |
实际 EE 11 Platform 所需模块及驱动装配 |
| JDBC | jdbc/Procurement、javax.sql.DataSource |
相同 JNDI 逻辑名、独立凭证/库与 PostgreSQL 驱动 |
| HTTP | /procurement 上下文根、/api REST 前缀 |
同一外部 URL 契约或记录受控映射 |
| 身份 | 目标受管身份与角色映射 | 同一合成主体、组织关联和越权拒绝语义 |
| 事务 | 受管事务与受控 SQL 更新 | 同一提交/回滚行集合及异常映射 |
| Messaging | 目标消息资源、outbox 与账本 | 同类可重投与恢复路径、记录 provider 差异 |
表中后四项是目标对照项,不是声称工程目前已完成这些功能。server.xml 的数据源现在明确含 serverName="127.0.0.1"、databaseName="javaee_lab" 和环境口令名,新运行时需以它自己的受管资源配置绑定同一逻辑 JNDI 名,数据库实例和密码改为隔离副本。不应把厂商部署文件直接打包进 WEB-INF/lib;DataSource 是容器资源,javax.sql 是 Java SE 类型,两者在 EE 11 中仍需分别配置。另一服务器可能有不同连接池、JTA 恢复存储、会话序列化或消息适配器参数;这些操作差异应记为显式配置差,不把可移植性等同于零配置。
把故障放在能定位的一层
部署到第二服务器后,先保留原服务器的已知用例输出供对照,两个实例各有自己数据库、端口和日志目录;一次只向一个环境发请求。服务器对安全异常的包装与文本描述可能不同,因此比较目标是“未认证不得审批、跨租户不可见、余额或金额不变”,而不是异常栈逐行相同。数据库角色权限也要对齐:若第二运行时用管理员账户连接,迁移脚本和读写操作即使成功,也遮住了最小权限配置错误;应在两个库为应用配置专用受限角色。重新部署与重启后复测同一 JNDI 与 schema,防止旧连接池仍指向上次库配置。
消息在第二容器上尤其容易被一张健康页面掩盖。broker 地址、连接工厂、目标队列、确认模式、死信与重投限制、outbox 扫描任务的恢复策略都需要迁移映射;即使 Platform 11 提供 Jakarta Messaging,具体 broker 资源与故障恢复仍是实现配置。若采购系统尚未实现这些业务链,不必在第二运行时临时生成假消息来填验收格子,标 NOT_RUN 并写缺少的代码/外部设施即可。日志中的关联 ID 需贯穿两个环境,以便比较同一合成申请的 SQL、事务和消息行。
已用相同 SHA-256 为 691a0acb9811be0a1d3ee1c9ede81ed33e5f5a2ce1e0f7b6c452a6f67969a0d4 的 WAR 部署 GlassFish 8.0.4;用 GlassFish 的 JDBC 资源 jdbc/Procurement 接入 pgJDBC 42.7.7。scenarios/00-health.sh、05-datasource.sh、06-servlet.sh 在端口 8080 上退出 0,前者只说明 Web 路由,后两者说明本次受管连接探针和 UTF-8 请求入口可响应;启动、资源探测与发行物摘要见 writing-plans/javaee-enterprise/verification/20261004T-glassfish-transfer/。这些实验使用原有 javaee_lab 实验库,没有隔离出可与原运行时逐行对照的第二数据库。错误 JNDI 名和错误凭证注入均未执行,不能从正常连接推断失败时机或恢复能力。
业务层接着回放相同采购请求:服务器核价、状态从草稿到提交、审批到下单,验证独立库的状态/版本/订单唯一约束;让明细插入后抛异常检查申请和明细一起回滚。并发审批必须通过同一 SQL 版本条件和数据库最终行判断,不能拿第二服务器抛出的异常类名与第一服务器完全一致当作可移植性必要条件。重试丢失 HTTP 响应,检查同一业务键只有一张订单;若 outbox 与 broker/消费者已构建,再检查重投、毒消息、死信及通知账本,确认新 provider 的投递和确认语义。没有 broker 时,这一列应写 NOT_RUN,不能只跑 SQL 就标消息矩阵通过。
权限层比 db-check 更关键。应以已认证的申请人、审批员、管理员及匿名身份,对相同租户/跨租户 ID、金额限额和角色入口执行拒绝矩阵;新运行时基本用户存储的创建不保证旧运行时中的 principal/组映射自动迁移。错误角色映射可能导致“安全注解还在,实际人人都能批”。每条拒绝用例都同时检查 HTTP、事务结果与敏感字段未泄漏;如果只做了未认证教学模式 /api/lab/requests,必须把角色/租户安全整列标未验证。不要让 JAVAEE_DEMO_MODE=true 在第二运行时对公网开启以求顺利验收。
差异表要能给下一位运行人员复跑
第二容器正常路径:从可信发行物核验二进制与兼容声明,部署隔离 WAR,确认特性/模块和驱动,建立资源绑定、主机只监听实验网卡,依次测试健康、数据库、业务、权限、事务、消息,记录每步命令、版本、脱敏响应、SQL 和服务器日志。失败路径至少有资源名不匹配、数据库凭证错误、受管事务回滚及跨租户请求;出现故障后单独恢复配置重跑同一用例。恢复操作不能删除消息账本或协调器日志,否则重试/事务验收没有可比依据。若原运行时的某个先修章节自身是 NOT_RUN,跨运行时比较只能写“双方未得可比证据”,不能把第二容器的独立成功冒充主线完整验证。
GlassFish 8.0.4 ZIP 已和官方下载页提供的 SHA-256 对照;M12 公开 TCK 页面仍不能代表 8.0.4 二进制的认证结果。实际 asadmin 部署、创建资源和 ping 的退出码见 20261004T-glassfish-transfer/。端口 8080、8181、4848 的实验监听均配置为回环,JAVAEE_DEMO_MODE=true 只可在本机隔离使用。2026-10-05 按现有脚本执行 09、18、23 均退出 0:采购金额 13.75、订单一张,故障注入后申请行数零,outbox 失败后仍为 PENDING、重试尝试次数变 2。11 的初次脚本因两款 Faces 实现的表单隐藏字段与属性顺序不同而失败;从实际 GET 页面提交 approval=approval 并兼容 input 属性后重新执行,顺序审批最终 APPROVED|2,见 verification/20261005T-glassfish-scenarios/。这些是同一共享实验库中的不同租户样本,不是隔离库重放;错误资源恢复、正式身份/权限、MDB、死信、独立 broker、运行时重启后业务矩阵仍 NOT_RUN,整篇实验只可标 PARTIAL。
实测结果应按最小表格逐行填“版本/输入/旧运行时证据/新运行时证据/差异/结论”:例如错误 JNDI 名是第二服务器部署失败或首次使用失败,恢复配置后用相同 SQL 才可写恢复成功;错误数据库口令时两边均须拒绝连接而不能回落到本地测试库;撤销审批员权限时两边均不能变更申请状态。将未测项留为 NOT_RUN 比填“规范支持,推测通过”有用。遇到 GlassFish 版本的厂商声明与公示 TCK 文档版本不一致时,只据实写各页对应的版本及 Java 组合;自行跑出的局部兼容矩阵也不是官方 TCK 认证。
移植矩阵最后必须有重启后的业务结果。健康路由和 DataSource 刚配置完时正常,不表示重新部署后连接池还加载正确驱动,也不表示消息消费者会从原 outbox 游标继续。两台运行时各自在其隔离库创建同一业务状态、停机重启,再检查申请与订单行、未消费任务和有权限的查询结果;若恢复行为不同,应记录目标版本与具体资源配置,而不是以“符合 Platform 11”抹平差异。重启后匿名及跨租户拒绝同样要重跑,防止只在初始化时临时配置了身份映射。
报告每个格子应写证据责任人可复核的材料:调用命令、实际退出码、响应状态和受限正文、数据库查询语句及行数、服务器资源名字和脱敏日志路径。未跑的环境不能填预期结果伪装实测,也不建议在共享主机上为实验直接停数据库或 broker。若需要定位迁移失败,先用两款服务器上的同一业务 ID 与 schema 校验值排除输入差异,再逐一比较资源解析、事务登记、角色和消息资源;同一 WAR 不能消除这些基础设施差异。
第二运行时若改变默认时区、字符集或 JSON 日期格式,采购申请金额和状态仍可能正确,审计时间和导出文本却不一致。对照时需固定数据库 timestamptz 读取与对外编码、核对含非 ASCII 供应商名的响应,并将不一致标为配置或协议差异;不能用健康端点覆盖这些业务输出。完整验收仍要求身份与消息链存在,未实现章节不能由 E08 单独补证。
两道带答案的练习
练习一: GlassFish 返回 /procurement/api/health 的 ready,但 /api/db-check 失败,工程师决定把 jdbc/Procurement 改成当前数据库的 JDBC URL 直接写死到代码里。能否据此宣布移植成功?
解: 不能。先核对第二运行时真实资源绑定的 JNDI 名、驱动、库名、角色凭证及根因是部署期还是借连接期;保留受管 DataSource 抽象,改隔离配置后重新测 db-check 和业务事务及回滚。直接硬编码 URL 绕过受管资源、可能指向错误库,且一次连接成功仍不能证明权限/消息。这里的故障是验收设计,未实测。
练习二: 原运行时的采购下单正常,第二运行时也正常,但两边均使用可伪造的 X-Lab-Tenant,第二运行时还未接 broker。是否可以把“完全可移植”写入结论?
解: 不行。当前同一 WAR 在第二运行时的单租户采购 SQL、受管回滚和 outbox 尝试已有受限实测;跨租户对象授权无法由 lab header 证明,消息未接入则该矩阵是 NOT_RUN。先补正式身份和角色映射及 broker/消费者,复跑拒绝和重投路径,再依结果给出可移植部分与不可移植配置。
官方版本资料与结论范围
参考 Jakarta EE 11 Platform、Jakarta EE 11 兼容产品与认证入口、Open Liberty 26.0.0.5 EE 11 功能说明、GlassFish 官方下载 与 GlassFish 8.0.0-M12 TCK 页面。最后一条对应 M12,不是 8.0.4;产品下载页、兼容清单和真实移植测试各有证据范围。主线实际 server.xml 和脚本位于 examples/javaee-enterprise/,第二服务器配置仅在本地私有临时目录,脱敏命令、二进制与 WAR 摘要、退出码位于上述验证记录;配置本身未归档,不具备即刻复现的完整环境快照。






