副标题:手动维护 Feature 版本太痛苦?这一招教你实现 server.xml 的”自动驾驶”。


⚠️ 常见错误提示(报错码速查)

如果你在启动 Open Liberty 时遇到以下错误,说明你掉入了”版本依赖地狱”:

CWWKF0033E: The singleton features mpHealth-3.0 and mpHealth-4.0 are colliding.
CWWKF0032E: An incompatible feature combination was detected: jaxrs-3.0 with jaxrs-4.0.

如果你正在面对这些报错,本文将带你用 Versionless 方式彻底根治! 🛠️

Read more: 告别 CWWKF0033E 冲突:Open Liberty Versionless 详解,终结 Jakarta EE 依赖地狱

引言:Java 开发者的”依赖地狱”

如果你曾经开发过 Java EE / Jakarta EE 应用,你一定遇到过这样的场景:

场景 1:版本冲突

<!-- 你配置了这些 features -->
<feature>servlet-5.0</feature>
<feature>jpa-3.0</feature>
<feature>jaxrs-3.0</feature>
<feature>mpHealth-3.0</feature>

然后启动服务器,看到这样的错误:

CWWKF0033E: The singleton features mpHealth-3.0 and mpHealth-4.0 are coliding.
CWWKF0032E: An incompatible fature combination was detected: 
  jaxrs-3.0 with jaxrs-4.0.

为什么会冲突?
因为 jpa-3.0 依赖 mpHealth-3.0,而 jaxrs-3.1 依赖 mpHealth-4.0。你需要手动查找所有依赖关系,然后选择合适的版本组合。


场景 2:升级噩梦

你正在使用 Jakarta EE 9.1,现在想升级到 10.0。你需要:

  1. 手动修改 所有 feature 版本号:
    • servlet-5.0 → servlet-6.0
    • jpa-3.0 → jpa-3.1
    • jaxrs-3.0 → jaxrs-3.1
    • … (可能有 20+ features)
  2. 祈祷没有版本冲突
  3. 如果冲突了,回到场景 1

开发体验极差! 😫


Open Liberty 的解决方案:Versionless Features

核心理念:开发者只需要关心 “我需要什么功能”,而不是 “这个功能用什么版本”

传统方式 vs Versionless 方式

❌ 传统方式(指定版本)

<featureManager>
    <feature>servlet-6.0</feature>
    <feature>jpa-3.1</feature>
    <feature>jaxrs-3.1</feature>
    <feature>jsonp-2.1</feature>
    <feature>jsonb-3.0</feature>
    <feature>mpHealth-5.0</feature>
    <feature>mpMetrics-6.0</feature>
</featureManager>

问题:

  • ❌ 需要记住每个 feature 的版本号
  • ❌ 需要手动解决版本冲突
  • ❌ 升级平台时,需要修改 每一个 feature 版本

✅ Versionless 方式(不指定版本)

<featureManager>
    <!-- 声明平台 -->
    <platform>jakartaee-10.0</platform>
    <platform>microProfile-7.0</platform>
    
    <!-- 只声明功能,不声明版本 -->
    <feature>servlet</feature>
    <feature>jpa</feature>
    <feature>jaxrs</feature>
    <feature>jsonp</feature>
    <feature>jsonb</feature>
    <feature>mpHealth</feature>
    <feature>mpMetrics</feature>
</featureManager>

优势:

  • ✅ 不需要记住版本号 – Open Liberty 自动选择合适的版本
  • ✅ 自动解决版本冲突 – 平台保证了所有 feature 版本兼容
  • ✅ 升级简单 – 只需要修改 <platform> 版本号,所有 features 自动升级

工作原理:Platform是核心

什么是平台(Platform)?

平台是一个 预测试、预验证的 feature 版本组合,保证所有 features 之间 100% 兼容

Open Liberty 支持 3 类平台:

平台类型版本示例包含的 Features
Jakarta EE8.0, 9.1, 10.0servlet, jpa, jaxrs, jsonp, jsonb, cdi, beans, …
Java EE6.0, 7.0, 8.0(旧版 Jakarta EE)
MicroProfile4.0, 4.1, 5.0, 6.0, 7.0mpConfig, mpHealth, mpMetrics, mpOpenAPI, …

版本解析规则

当你声明:

<platform>jakartaee-10.0</platform>
<feature>servlet</feature>
<feature>jpa</feature>

Open Liberty 会:

  1. 查找 Jakarta EE 10.0 平台定义
  2. 解析 servlet → servlet-6.0 (Jakarta EE 10.0 中的版本)
  3. 解析 jpa → jpa-3.1 (Jakarta EE 10.0 中的版本)
  4. 验证 所有 features 版本兼容
  5. 启动 服务器

你完全不需要关心版本号! 🎉


实战演示:从”依赖地狱”到”一键配置”

场景:构建一个 RESTful Web 应用(Jakarta EE + MicroProfile)

❌ 传统方式(痛苦)

Step 1: 查找依赖关系

你需要手动查找:

  • Jakarta EE 10.0 包含哪些 feature 版本?
  • MicroProfile 7.0 包含哪些 feature 版本?
  • 它们之间是否有冲突?

你花了 2 小时阅读文档… ⏳


Step 2: 配置 server.xml

<featureManager>
    <!-- Jakarta EE 10.0 features -->
    <feature>servlet-6.0</feature>
    <feature>jpa-3.1</feature>
    <feature>jaxrs-3.1</feature>
    <feature>jsonp-2.1</feature>
    <feature>jsonb-3.0</feature>
    <feature>cdi-4.0</feature>
    <feature>beans-5.0</feature>
    
    <!-- MicroProfile 7.0 features -->
    <feature>mpConfig-4.0</feature>
    <feature>mpHealth-5.0</feature>
    <feature>mpMetrics-6.0</feature>
    <feature>mpOpenAPI-4.0</feature>
</featureManager>

Step 3: 启动服务器,遇到冲突

CWWKF0033E: The singleton features mpMetrics-5.0 and mpMetrics-6.0 are coliding.
CWWKF0032E: An incompatible fature combination was detected.

你又花了 1 小时调试… 🤬


Step 4: 升级到 Jakarta EE 11.0

你需要手动修改 每一个 feature 版本号:

<!-- 修改前 -->
<feature>servlet-6.0</feature>
<feature>jpa-3.1</feature>
...

<!-- 修改后(你花了 30 分钟,还改错了 2 个) -->
<feature>servlet-6.1</feature>
<feature>jpa-3.2</feature>
...

开发体验:😫😫😫


✅ Versionless 方式(愉悦)

Step 1: 声明平台

<featureManager>
    <platform>jakartaee-10.0</platform>
    <platform>microProfile-7.0</platform>
</featureManager>

耗时:30 秒 ⚡


Step 2: 添加需要的 features(不需要版本号)

<featureManager>
    <platform>jakartaee-10.0</platform>
    <platform>microProfile-7.0</platform>
    
    <!-- 只声明功能,不声明版本 -->
    <feature>servlet</feature>
    <feature>jpa</feature>
    <feature>jaxrs</feature>
    <feature>jsonp</feature>
    <feature>jsonb</feature>
    <feature>mpConfig</feature>
    <feature>mpHealth</feature>
    <feature>mpMetrics</feature>
</featureManager>

耗时:1 分钟 ⚡


Step 3: 启动服务器

CWWKF0012I: The server installed the following features:
  servlet-6.0, jpa-3.1, jaxrs-3.1, jsonp-2.1, jsonb-3.0,
  cdi-4.0, beans-5.0, mpConfig-4.0, mpHealth-5.0, mpMetrics-6.0
CWWKF0011I: The defaultServer server is ready to run a smarter planet.

没有冲突! ✅
没有错误! ✅
你节省了 3+ 小时! 🎉


Step 4: 升级到 Jakarta EE 10.0

只需要修改 一行

<!-- 修改前 -->
<platform>jakartaee-9.1</platform>

<!-- 修改后 -->
<platform>jakartaee-10.0</platform>

所有 features 自动升级! 🚀


三种使用方式

Open Liberty 提供 3 种方式 使用 versionless features。

方法 1:显式 platform 元素(推荐)⭐⭐⭐⭐⭐

<featureManager>
    <platform>jakartaee-10.0</platform>
    <platform>microProfile-7.0</platform>
    
    <feature>servlet</feature>
    <feature>jpa</feature>
    <feature>mpHealth</feature>
</featureManager>

优势:

  • ✅ 最明确(代码即文档)
  • ✅ 版本控制友好(可以 diff)
  • ✅ 推荐方式

方法 2:环境变量 PREFERRED_PLATFORM_VERSIONS

Step 1: 配置 server.env

PREFERRED_PLATFORM_VERSIONS=microProfile-7.0,jakartaee-10.0

Step 2: 在 server.xml 中使用 versionless features

<featureManager>
    <feature>servlet</feature>
    <feature>jpa</feature>
    <feature>mpHealth</feature>
</featureManager>

⚠️ 注意:

  • ❌ 如果只在 shell 中设置环境变量,打包服务器时会丢失
  • ✅ 推荐在 server.env 中设置(会包含在打包文件中)

方法 3:隐式平台声明(不推荐)

如果你启用了 只有一个平台包含的 versioned feature,Open Liberty 会自动推断平台。

<featureManager>
    <!-- mpHealth-3.0 只在 MicroProfile 4.0 中存在 -->
    <feature>mpHealth-3.0</feature>
    
    <!-- 自动推断:使用 MicroProfile 4.0 平台 -->
    <feature>mpMetrics</feature>
    <feature>mpConfig</feature>
</featureManager>

⚠️ 不推荐理由:

  • ❌ 隐式行为(代码不清晰)
  • ❌ 如果 feature 在多个平台中存在,会失败
  • ❌ 调试困难

平台参考:所有可用的 Versionless Features

MicroProfile 平台

参考https://openliberty.io/docs/latest/reference/feature/platform/MicroProfile.html

MicroProfile 版本包含的 Versionless Features
7.0mpConfig, mpHealth, mpMetrics, mpOpenAPI, mpRestClient, …
6.0mpConfig, mpHealth, mpMetrics, mpOpenAPI, mpRestClient, …
5.0mpConfig, mpHealth, mpMetrics, mpOpenAPI, mpRestClient, …

Jakarta EE 平台

参考https://openliberty.io/docs/latest/reference/feature/platform/JakartaEE.html

Jakarta EE 版本包含的 Versionless Features
10.0 (Stable)servlet, jpa, jaxrs, jsonp, jsonb, cdi, beans, …
9.1servlet, jpa, jaxrs, jsonp, jsonb, cdi, beans, …

Java EE 平台(旧版)

参考https://openliberty.io/docs/latest/reference/feature/platform/JavaEE.html

Java EE 版本包含的 Versionless Features
8.0servlet, jpa, jaxrs, jsonp, cdi, beans, …
7.0servlet, jpa, jaxrs, jsonp, cdi, beans, …

最佳实践

✅ 推荐做法

  1. 使用 Versionless Features – 永远不要再手动指定版本号
  2. 使用显式 platform 元素 – 最明确,最易维护
  3. 在 server.xml 中声明 platform – 版本控制友好
  4. 检查平台文档 – 确认 feature 是否在平台中
  5. 使用稳定的平台版本 – 例如 Jakarta EE 10.0

❌ 避免的做法

  1. 避免混合 versioned 和 versionless features – 选择一种方式
  2. 避免使用隐式平台声明 – 代码不清晰
  3. 避免在 shell 中设置 PREFERRED_PLATFORM_VERSIONS – 使用 server.env
  4. 避免假设所有 features 都有 versionless 版本 – 检查平台文档
  5. 避免使用过新的平台版本 

配置示例

server.xml

<featureManager>
    <!-- 平台声明 -->
    <platform>microProfile-7.0</platform>
    <platform>jakartaee-10.0</platform>
    
    <!-- Versionless Features (自动解析) -->
    <feature>servlet</feature>
    <feature>jpa</feature>
    <feature>jaxrs</feature>
    <feature>jsonp</feature>
    <feature>jsonb</feature>
    <feature>beans</feature>
    <feature>cdi</feature>
    
    <!-- MicroProfile Versionless Features -->
    <feature>mpConfig</feature>
    <feature>mpHealth</feature>
    
    <!-- Security Features (versioned - 不在平台中) -->
    <feature>appSecurity-5.0</feature>
    <feature>transportSecurity-1.0</feature>
</featureManager>

解析后的版本:

Versionless Feature解析后版本来源平台
servletservlet-6.0Jakarta EE 10.0
jpajpa-3.1Jakarta EE 10.0
jaxrsjaxrs-3.1Jakarta EE 10.0
jsonpjsonp-2.1Jakarta EE 10.0
jsonbjsonb-3.0Jakarta EE 10.0
mpConfigmpConfig-4.0MicroProfile 7.0
mpHealthmpHealth-5.0MicroProfile 7.0

升级场景:从 Jakarta EE 10.0 到 11.0

传统方式: 需要修改 7 个 feature 版本号
Versionless 方式: 只需要修改 1 行

<!-- 修改前 -->
<platform>jakartaee-10.0</platform>

<!-- 修改后 -->
<platform>jakartaee-11.0</platform>

所有 features 自动升级! 🚀


常见问题(FAQ)

Q1: 所有 features 都支持 versionless 吗?

A: 不是。只有 包含在平台中的 features 才有 versionless 版本。

示例:

  • ✅ servlet – 在 Jakarta EE 平台中
  • ✅ mpHealth – 在 MicroProfile 平台中
  • ❌ springBoot – 不在任何平台中,所以没有 versionless 版本

Q2: 我可以同时使用多个平台吗?

A: 可以!最多可以同时使用 2 个平台

  • 一个 MicroProfile 平台
  • 一个 Jakarta EE 或 Java EE 平台

示例:

<featureManager>
    <platform>microProfile-7.0</platform>
    <platform>jakartaee-10.0</platform>
</featureManager>

Q3: Versionless features 会影响性能吗?

A: 不会。版本解析只在 服务器启动时 进行一次,运行时性能 零影响


Q4: 我可以混合使用 versioned 和 versionless features 吗?

A: 可以,但 不推荐。建议选择一种方式,保持配置清晰。

示例(不推荐):

<featureManager>
    <platform>jakartaee-10.0</platform>
    
    <!-- Versionless (推荐) -->
    <feature>servlet</feature>
    <feature>jpa</feature>
    
    <!-- Versioned (不推荐混合) -->
    <feature>springBoot-3.0</feature>
</featureManager>

更好的方式:

<featureManager>
    <platform>jakartaee-10.0</platform>
    
    <!-- Versionless (平台中的 features) -->
    <feature>servlet</feature>
    <feature>jpa</feature>
    
    <!-- Versioned (不在平台中的 features) -->
    <feature>springBoot-3.0</feature>
</featureManager>

Q5: 如何查看 versionless feature 解析后的版本?

A: 查看 Liberty 日志:

CWWKF0012I: The server installed the following features:
  servlet-6.0, jpa-3.1, jaxrs-3.1, ...

或者使用 featureManager 的 report-versions 目标:

mvn liberty:report-versions

结论:Versionless Features 改变了什么?

传统开发体验 😫

  1. 手动查找 feature 版本号 ⏳
  2. 手动解决版本冲突 🤬
  3. 升级平台时修改 N 个版本号 😫
  4. 维护成本高 💸

Versionless 开发体验 🚀

  1. 声明平台 – 30 秒 ⚡
  2. 添加 features(无版本号) – 1 分钟 ⚡
  3. 自动解决冲突 – 零耗时 ✅
  4. 升级只需要修改 1 行 – 10 秒 ⚡
  5. 维护成本低 💰