Apache Neethi 3.2.2 介绍与核心概念详解
介绍 Apache Neethi 3.2.2 的定位、WS-Policy 组合模型(Policy/All/ExactlyOne)与断言构建器机制,并给出日志与策略框架选型对比。
Apache Neethi 3.2.2 介绍与核心概念详解
目标:理解 Apache Neethi 3.2.2 的 WS-Policy 实现模型(组合算子、断言、构建器、规范化)与它在 Apache 服务栈中的位置。文中结论与回显均来自 Ubuntu 22.04(OpenJDK 17)实测。
一、环境信息
| 项目 | 值 |
|---|---|
| 操作系统 | Ubuntu 22.04.5 LTS |
| 系统架构 | x86_64(amd64) |
| JDK | OpenJDK 17.0.20.1 |
| Maven | Apache Maven 3.6.3 |
| 组件版本 | Apache Neethi 3.2.2(Maven Central org.apache.neethi:neethi) |
| XML 依赖 | axiom-api/axiom-impl 1.3.0(Neethi 官方 POM 声明为 provided) |
| 实验目录 | /opt/neethi-demo |
表后逐项说明:Neethi 是纯 Java 库,无 JDK 版本强制(本实验 17 通过);它只管策略模型,XML 解析交给 AXIOM(Apache 置 AXIOM 1.3.0 为 provided,因此使用方必须自己显式引入 axiom-api 与运行时实现 axiom-impl);实验项目在 /opt/neethi-demo。
二、概述
Apache Neethi 是 WS-Policy 规范(WS-Policy 1.5,W3C 标准,命名空间 http://www.w3.org/ns/ws-policy)的 Java 实现,提供策略文档的解析、模型化、合并、规范化与序列化能力。它本身不定义任何具体断言(如安全断言),而是提供"承载断言的框架"——上层框架(Apache CXF、Rampart、Sandesha2 等)在其上注册业务断言的构建器。
Maven Central 坐标与依赖(mvn dependency:tree 实测):
[INFO] --- maven-dependency-plugin:2.8:tree (default-cli) @ neethi-demo ---
[INFO] com.example:neethi-demo:jar:1.0.0
[INFO] +- org.apache.neethi:neethi:jar:3.2.2:compile
[INFO] +- org.apache.ws.commons.axiom:axiom-api:jar:1.3.0:compile
[INFO] | +- commons-logging:commons-logging:jar:1.2:compile
[INFO] | +- jaxen:jaxen:jar:1.2.0:compile
[INFO] | +- org.apache.james:apache-mime4j-core:jar:0.8.4:compile
[INFO] | \- jakarta.activation:jakarta.activation-api:jar:1.2.1:compile
[INFO] \- org.apache.ws.commons.axiom:axiom-impl:jar:1.3.0:runtime
[INFO] \- com.fasterxml.woodstox:woodstox-core:jar:6.2.6:runtime
[INFO] \- org.codehaus.woodstox:stax2-api:jar:4.2.1:runtime
逐项说明:neethi 3.2.2 本体不带任何 XML 解析器;axiom-api 是 OM 树接口(compile 引入其附属依赖),axiom-impl 是实现(runtime),其下传递 woodstox 作为 StAX 实现;官方 POM 中这三个 axiom 构件均声明为 provided,所以业务工程必须像上面这样显式添加。
💡 技术拓展:WS-Policy 的"合并算法"有两个方向——merge(取两个策略的笛卡尔组合,结果是"都满足"的超集策略)与 intersect(取交集,结果是双方共同接受的方案);两者都依赖 WS-Policy 的组合算子语义(ExactlyOne 是"或"、All 是"且")。本文实验采用 merge + normalize 展示组合语义(实测 2 与 1 的 alternatives 合并规范化后得 8 个),intersect 用于服务端与客户端的策略协商场景,将在 WS-Policy 配置详解篇展开。
三、核心架构
3.1 组合模型(Policy/All/ExactlyOne)
| 模型对象 | WS-Policy 元素 | 语义 |
|---|---|---|
| Policy | wsp:Policy | 策略根,内部等价一个 ExactlyOne |
| All | wsp:All | 交集(且):子断言必须同时满足 |
| ExactlyOne | wsp:ExactlyOne | 并集(或):任选一个子项满足即可 |
| PolicyReference | wsp:PolicyReference | 引用另一策略(按 URI/ID) |
表后逐项说明:三者均实现 CompositeAssertion;一个"可选方案"(alternative)= 一条从根到叶的 All 路径;Policy 的 getAlternatives() 返回 Iterator 列表,每个元素是 List<Assertion>(实测 API 签名:public java.util.Iterator<java.util.List<org.apache.neethi.Assertion>> getAlternatives())。
3.2 断言模型
| 类型 | 类 | 说明 |
|---|---|---|
| 断言接口 | org.apache.neethi.Assertion | getName/isOptional/isIgnorable/serialize/normalize |
| 原子断言 | org.apache.neethi.builders.PrimitiveAssertion | 带 QName、属性表、文本值 |
| 含嵌套策略的断言 | PolicyContainingPrimitiveAssertion | 元素内嵌 wsp:Policy 时生成(实测见下) |
| 引用断言 | PolicyReference | wsp:PolicyReference 的模型 |
| 可协商断言 | IntersectableAssertion | 支持 intersect 的扩展接口 |
嵌套解析实测(policy3.xml 中 TransportBinding 内嵌 wsp:Policy):
top assertion: {http://schemas.xmlsoap.org/ws/2005/07/securitypolicy}TransportBinding class=PolicyContainingPrimitiveAssertion
nested: {http://schemas.xmlsoap.org/ws/2005/07/securitypolicy}TransportToken class=PolicyContainingPrimitiveAssertion
nested: {http://schemas.xmlsoap.org/ws/2005/07/securitypolicy}IncludeTimestamp class=PrimitiveAssertion
逐项说明:元素内有子 wsp:Policy 时解析为 PolicyContainingPrimitiveAssertion(getPolicy() 可下钻),否则是普通 PrimitiveAssertion;嵌套可无限层。
3.3 构建器与工厂机制
- org.apache.neethi.builders.AssertionBuilder<T> 是泛型接口:build(T, AssertionBuilderFactory) 返回 Assertion,getKnownElements() 返回 QName[](实测 javap 签名)。
- 内建构建器:XMLPrimitiveAssertionBuilder implements AssertionBuilder<org.w3c.dom.Element>,处理"未知命名空间断言"的兜底,也是自定义构建器的推荐基类。
- 发现机制:java.util.ServiceLoader 加载 META-INF/services/org.apache.neethi.builders.AssertionBuilder 文件里列出的实现类;本实验自定义 QosAssertionBuilder 后,解析 qos 断言时输出实测日志:
[QosAssertionBuilder] building assertion for {http://example.org/qos}ReliableMessaging
[QosAssertionBuilder] building assertion for {http://example.org/qos}Compression
[QosAssertionBuilder] building assertion for {http://example.org/qos}Auditing
3.4 策略操作与注册表
- merge(Policy other):合并,产生包含双方方案的组合策略(合并后规范化前是嵌套结构)。
- normalize(boolean deep):把嵌套组合展开成"ExactlyOne(All...)"的平铺正则形,deep=true 时递归展开嵌套策略。
- intersect(Policy other):求交集(策略协商)。
- serialize(XMLStreamWriter):序列化回 WS-Policy XML。
- PolicyRegistry / PolicyRegistryImpl:以字符串键缓存策略对象,接口只有 register/lookup/remove 三个方法(实测 javap:public abstract void register(java.lang.String, org.apache.neethi.Policy); public abstract org.apache.neethi.Policy lookup(java.lang.String); public abstract void remove(java.lang.String);)。
3.5 输入源与转换器
PolicyEngine 提供多个静态入口(实测 javap):
public static org.apache.neethi.Policy getPolicy(java.io.InputStream);
public static org.apache.neethi.Policy getPolicy(org.apache.axiom.om.OMElement);
public static org.apache.neethi.Policy getPolicy(java.lang.Object);
逐项说明:InputStream 最常用;OMElement 走 AXIOM 树;Object 版本经 builders.converters.ConverterRegistry 自动在 DOM/StAX/OM 间转换(converters 包含 DOMToOMConverter、StaxToDOMConverter 等 8 种双向转换器)。
四、功能特性
- 标准合规:完整实现 WS-Policy 1.5 的组合算子、Optional/Ignorable 语义与 PolicyReference。
- 可插拔断言:ServiceLoader 或 PolicyEngine.registerBuilder(QName, AssertionBuilder) 注册自定义断言构建器。
- 规范化与合并:normalize 展开可选断言(实测 1 个策略含 2 个 optional 断言规范化后得 4 个 alternative),merge 取笛卡尔组合(实测 2 与 1 合并规范化得 8 个)。
- 多输入源:InputStream/OMElement/DOM/StAX 经转换器统一处理。
- 序列化输出:Policy/Assertion 均可写回 XMLStreamWriter,便于回传或落库。
- 轻量:本体 jar 约 100KB 级,运行时只依赖 AXIOM。
五、适用场景
- Web 服务框架内嵌:CXF/Rampart 用 Neethi 解析 WSDL 内嵌策略并协商安全绑定。
- 自研网关/SDK:解析服务方发布的 WS-Policy 声明,校验自身能力是否匹配。
- 策略驱动配置:把"可选能力组合"(可靠性/压缩/审计等)声明成策略文件,运行期 merge/normalize 生成有效组合集合。
- 测试与教学:验证 WS-Policy 文档的组合语义(可选断言展开、合并交叉积)。
六、同类选型对比
| 维度 | Apache Neethi 3.2.2 | 自研 XML 解析 | Apache CXF 内嵌 policy 模块 | .NET WCF(非 Java) |
|---|---|---|---|---|
| 标准覆盖 | WS-Policy 1.5 全语义 | 按需实现 | 基于 Neethi | 完整 |
| 断言可插拔 | ServiceLoader/注册表 | 手写分发 | CXF 扩展点 | 配置驱动 |
| 合并/规范化 | 内建(merge/intersect/normalize) | 手写算法 | 内建 | 内建 |
| 依赖量 | AXIOM + StAX(woodstox) | 最小 | CXF 全家桶 | 平台自带 |
| 适用 | 框架/工具链集成 | 单点小需求 | SOA 全栈 | Windows 栈 |
表后逐项说明:需要独立策略引擎(不引 CXF 全栈)时 Neethi 是 Java 生态事实标准;只有一两个固定策略文档、不涉及合并语义时自研解析更轻;CXF 用户则直接用其 policy 模块无需单独引 Neethi;跨语言与 .NET 互操作时注意双方对 Ignorable 的处理差异。
七、常见问题(FAQ)
Q1:Neethi 和 CXF 的关系是什么?单独用 Neethi 有意义吗? A:CXF 的 WS-Policy 支持构建在 Neethi 之上。做网关、SDK、配置引擎等只需"策略模型"的场景,单独引 Neethi(约 100KB 加 AXIOM)即可,无需 CXF 全栈;要做完整 WS-Security 协商则用 CXF。
Q2:为什么引入 neethi 后运行还是报 ClassNotFound(axiom 相关)? A:官方 POM 把 axiom-api/axiom-impl/axiom-dom 声明为 provided scope,不会传递。必须显式添加 org.apache.ws.commons.axiom:axiom-api:1.3.0(compile)与 axiom-impl:1.3.0(runtime),axiom-impl 会带 woodstox StAX 实现(实测依赖树)。
Q3:Policy.getAlternatives() 为什么不能直接 for-each? A:3.2.2 的 Policy 未实现 Iterable,getAlternatives() 返回 java.util.Iterator<java.util.List<Assertion>>(实测 javap)。需用 while/for 配合 Iterator 显式迭代;每个元素是一条 alternative(断言列表)。
Q4:自定义断言构建器怎么被框架发现? A:两种方式:在 classpath 放 META-INF/services/org.apache.neethi.builders.AssertionBuilder 文件(内容为实现类全名,走 ServiceLoader);或代码里 PolicyEngine.registerBuilder(QName, builder) 注册。本实验用前者,解析 qos 命名空间断言时自动回调(实测输出 [QosAssertionBuilder] building assertion for ...)。
Q5:getKnownElements() 返回什么类型? A:QName[](数组),不是 List。实测接口签名 public abstract javax.xml.namespace.QName[] getKnownElements()。这是 3.x 与旧版文档常见差异点。
Q6:wsp:Optional 的断言解析后如何区分? A:Assertion.isOptional() 返回 true。断言元素带 wsp:Optional="true" 属性时生效(实测 policy2.xml 中 qos:Compression wsp:Optional="true" 解析后 optional=true)。规范化(normalize)会把 optional 断言展开成"有/无"两个 alternative。
Q7:PolicyRegistry.lookup 找不到 key 会抛异常吗? A:不会,返回 null(实测:lookup not-exist -> null)。调用方需自行判空;remove 后再 lookup 同样返回 null。接口无 list-names 方法,键集合需调用方自管。
Q8:断言内嵌 wsp:Policy 时 Java 侧拿到什么对象? A:PolicyContainingPrimitiveAssertion(实现 PolicyContainingAssertion 接口),getPolicy() 返回嵌套 Policy 可继续下钻。实测 policy3.xml 中 TransportBinding/TransportToken 均为该类型,IncludeTimestamp(无嵌套)为普通 PrimitiveAssertion。
Q9:merge 之后直接用为什么 alternatives 数量"不对"? A:merge 的结果未必是正则形(可能嵌套 ExactlyOne/All),必须再 normalize(true) 才得到"ExactlyOne(All...)"平铺结构。实测 2 与 1 个 alternative 合并后未规范化显示 2,规范化后 8(含 optional 展开)。比较/序列化前都应 normalize。
Q10:Neethi 支持从 WSDL 里抽取策略吗? A:Neethi 只处理策略 XML 本身(InputStream/OMElement/DOM)。WSDL 级别的策略引用/附着(wsp:PolicyAttachment)需要上层框架(CXF)解析 WSDL 后把策略片段喂给 Neethi;本实验策略文件均为独立 XML 文档。
八、参考链接
- Apache Neethi 官方主页:https://neethi.apache.org/
- Neethi 3.2.2 Maven Central:https://repo.maven.apache.org/maven2/org/apache/neethi/neethi/3.2.2/
- Neethi 源码仓库:https://github.com/apache/neethi
- WS-Policy 1.5 W3C 标准:https://www.w3.org/TR/ws-policy/
- WS-PolicyAttachment 规范(Optional/Ignorable 语义来源):https://www.w3.org/Submission/WS-PolicyAttachment/
- Apache AXIOM:https://axiom.apache.org/
- Apache CXF WS-SecurityPolicy 文档(Neethi 上层应用):https://cxf.apache.org/docs/ws-securitypolicy.html