Apache Sandesha2 在 Ubuntu 22.04 集成使用指南
在 Ubuntu 22.04 从零集成 Axis2 1.6.2 与 Sandesha2 1.6.2:修复模块包资源缺陷、部署 RM 服务与客户端并实测跑通可靠序列,如实记录 Axis2 1.8.x 兼容性断裂报错。
Apache Sandesha2 在 Ubuntu 22.04 集成使用指南
目标:在一台 Ubuntu 22.04 服务器上从零完成 Apache Axis2 1.6.2 + Apache Sandesha2 1.6.2 的可靠消息(WS-ReliableMessaging)集成:下载与修复模块包、部署 Axis2、启用 sandesha2 模块、部署 RM 示例服务并用 RM 客户端实测跑通一条可靠序列,同时如实记录 Axis2 1.8.x 的兼容性断裂实测报错。
一、环境信息
本文所有命令与回显均在以下环境实测通过(一台 Ubuntu 22.04 x86_64 服务器,实验目录统一放在 /root):
- 操作系统:Ubuntu 22.04(x86_64)
- JDK:OpenJDK 1.8.0_504(OpenJDK 8;Sandesha2 1.6.2 时代组件必须用 JDK 6/7/8,JDK 17 会导致启动失败,见五、1)
- Apache Axis2:1.6.2(bin 发行包);对照测试用 1.8.2
- Apache Sandesha2:1.6.2(Maven Central
org.apache.sandesha2:sandesha2:1.6.2,packaging=mar) - 服务端监听端口:8080;客户端回调监听端口:6060
- 实测时间:2026-10-16
版本实测回显:
java -version
openjdk version "1.8.0_504"
OpenJDK Runtime Environment (build 1.8.0_504-8u504-ga-1ubuntu1~22.04.3-b01)
OpenJDK 64-Bit Server VM (build 25.504-b01, mixed mode)
二、前置条件
2.1 安装 JDK 8 与基础工具
Sandesha2 1.6.2 与 Axis2 1.6.x 均为 2011~2012 年代码,必须运行在 JDK 8 及以下版本。安装 OpenJDK 8 及下载/解包工具:
apt-get update
apt-get install -y openjdk-8-jdk curl wget unzip zip
实测回显(节选):
Setting up openjdk-8-jdk-headless:amd64 (8u504-ga-1ubuntu1~22.04.3) ...
Setting up openjdk-8-jdk:amd64 (8u504-ga-1ubuntu1~22.04.3) ...
⚠️ 注意:若服务器同时装有 JDK 17(Ubuntu 22.04 默认源里
default-jdk指向 17),Axis2 1.6.2 的启动脚本会因-Djava.endorsed.dirs参数被 JDK 9+ 拒绝而失败(详见五、1)。后续所有命令均显式把 JDK 8 前置到PATH。
验证 JDK 8 的 javac 可用:
export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64
export PATH=$JAVA_HOME/bin:$PATH
javac -version
实测回显:
javac 1.8.0_504
2.2 版本选型说明
Sandesha2 与 Axis2 存在强耦合(module.xml 的 MEP 写法、内核 API),版本组合以本文实测为准:
| 组件组合 | 实测结果 | 说明 |
|---|---|---|
| Axis2 1.6.2 + Sandesha2 1.6.2 + JDK 8 | ✅ RM 序列跑通 | 本文主线组合 |
| Axis2 1.8.2 + Sandesha2 1.6.2 + JDK 17 | ❌ 模块部署失败 | 断裂,报错见五、2 |
关键差异:Sandesha2 1.6.2 的 module.xml 使用 WS-Addressing 2006/01 WSDL 命名空间的 MEP URI,Axis2 1.8.x 不再接受;Axis2 1.6.x 则是 2012 年与 Sandesha2 1.6.2 同期开发、CI 验证的组合。结论:集成 Sandesha2 必须把 Axis2 钉在 1.6.x。
三、依赖引入
3.1 下载 Axis2 1.6.2 发行包
Axis2 全历史发行包在 Apache 归档目录 archive.apache.org/dist/axis/axis2/java/core/(实测该目录列出 1.5.2 至 2.0.1 全部版本)。下载 1.6.2 bin 包:
mkdir -p /root/dl && cd /root/dl
curl -O https://archive.apache.org/dist/axis/axis2/java/core/1.6.2/axis2-1.6.2-bin.zip
实测回显(下载完成后核对大小):
ls -la axis2-1.6.2-bin.zip
-rw-r--r-- 1 root root 20592286 Oct 16 04:00 axis2-1.6.2-bin.zip
3.2 下载 Sandesha2 1.6.2 模块包
Sandesha2 的项目归档目录(archive.apache.org/dist/ws/sandesha2/)实测只保留 0.9~1.3 旧版,1.6.2 只能取自 Maven Central。先实测确认坐标(org.apache.sandesha2 组下 artifact 清单):
curl -s https://repo1.maven.org/maven2/org/apache/sandesha2/ | grep -oE 'href="[^"]+/"'
实测回显:
href="../"
href="distribution/"
href="sandesha2/"
href="sandesha2-client/"
href="sandesha2-client-constants/"
href="sandesha2-core/"
href="sandesha2-interop/"
href="sandesha2-parent/"
href="sandesha2-persistence/"
href="sandesha2-policy/"
href="sandesha2-rampart-integration/"
href="sandesha2-resource-bundle/"
href="sandesha2-samples/"
href="sandesha2-tests/"
sandesha2 即模块本体(packaging=mar),版本目录实测为 1.1/ 1.2/ 1.3/ 1.4/ 1.6.0/ 1.6.1/ 1.6.2/。下载模块包与示例源码:
cd /root/dl
curl -O https://repo1.maven.org/maven2/org/apache/sandesha2/sandesha2/1.6.2/sandesha2-1.6.2.mar
curl -O https://repo1.maven.org/maven2/org/apache/sandesha2/sandesha2-core/1.6.2/sandesha2-core-1.6.2.jar
curl -O https://repo1.maven.org/maven2/org/apache/sandesha2/sandesha2-samples/1.6.2/sandesha2-samples-1.6.2-sources.jar
ls -la
实测回显:
-rw-r--r-- 1 root root 20592286 Oct 16 04:00 axis2-1.6.2-bin.zip
-rw-r--r-- 1 root root 406772 Oct 16 04:00 sandesha2-1.6.2.mar
-rw-r--r-- 1 root root 915245 Oct 16 04:11 sandesha2-core-1.6.2.jar
-rw-r--r-- 1 root root 30742 Oct 16 04:00 sandesha2-samples-1.6.2-sources.jar
⚠️ 注意:经实测,Maven Central 上不存在
org.apache.sandesha2:wso2/sandesha2这个坐标(HTTP 404),实际坐标为org.apache.sandesha2:sandesha2(mar)与org.apache.sandesha2:sandesha2-core(jar)。
3.3 修复 Maven Central mar 包的资源缺失缺陷(实测关键步骤)
直接把 sandesha2-1.6.2.mar 部署进 Axis2 1.6.2 会启动失败。实测报错(服务端日志原文):
[INFO] Deploying module: sandesha2-1.6.2 - file:/opt/axis2-1.6.2/repository/modules/sandesha2-1.6.2.mar
at org.apache.sandesha2.SandeshaModule.init(SandeshaModule.java:86)
Caused by: java.util.MissingResourceException: Cannot find resource 'org.apache.sandesha2.i18n.resource'
at org.apache.sandesha2.i18n.SandeshaMessageHelper.<clinit>(SandeshaMessageHelper.java:38)
[SimpleAxisServer] Shutting down. Error starting SimpleAxisServer
定位过程:解开 mar 与 core jar 对比(实测命令与回显):
cd /root/dl
unzip -l sandesha2-core-1.6.2.jar | grep -i i18n
0 2012-04-30 13:11 org/apache/sandesha2/i18n/
9375 2012-04-30 13:11 org/apache/sandesha2/i18n/SandeshaMessageKeys.class
18399 2012-04-30 13:10 org/apache/sandesha2/i18n/resource.properties
3563 2012-04-30 13:11 org/apache/sandesha2/i18n/SandeshaMessageHelper.class
即 Maven Central 的 mar 打包时漏掉了 resource.properties(该文件在 core jar 中存在)。修复:把该资源补进 mar:
mkdir -p /root/patch/org/apache/sandesha2/i18n
cd /root/patch
unzip -oq /root/dl/sandesha2-core-1.6.2.jar "org/apache/sandesha2/i18n/resource.properties"
cp /root/dl/sandesha2-1.6.2.mar /root/dl/sandesha2-1.6.2-patched.mar
zip -q /root/dl/sandesha2-1.6.2-patched.mar org/apache/sandesha2/i18n/resource.properties
unzip -l /root/dl/sandesha2-1.6.2-patched.mar | grep -E "resource.properties|module.xml"
实测回显:
8814 2012-04-30 13:12 META-INF/module.xml
18399 2012-04-30 13:10 org/apache/sandesha2/i18n/resource.properties
resource.properties 已在 mar 内,此 mar 即为后续部署使用的 sandesha2-1.6.2-patched.mar。
四、集成步骤
4.1 安装 Axis2 并部署 sandesha2 模块
解压 Axis2,放入补丁后的 sandesha2 模块(模块目录 repository/modules/,模块以 .mar 结尾;Axis2 启动时自动扫描部署):
cd /root/dl && unzip -q axis2-1.6.2-bin.zip -d /opt/
cp /root/dl/sandesha2-1.6.2-patched.mar /opt/axis2-1.6.2/repository/modules/sandesha2-1.6.2.mar
ls /opt/axis2-1.6.2/repository/modules/
实测回显:
addressing-1.6.2.mar
mex-1.6.2.mar
modules.list
mtompolicy-1.6.2.mar
ping-1.6.2.mar
sandesha2-1.6.2.mar
scripting-1.6.2.mar
soapmonitor-1.6.2.mar
4.2 启动 Axis2 服务端(JDK 8 前置 PATH)
export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64
export PATH=$JAVA_HOME/bin:$PATH
cd /opt/axis2-1.6.2/bin
nohup ./axis2server.sh > /root/axis162-run.log 2>&1 &
sleep 25
tail -4 /root/axis162-run.log
实测回显:
[INFO] Listening on port 8080
[INFO] [SimpleAxisServer] Started
[SimpleAxisServer] Started
验证模块加载与服务可用:
grep -iE "sandesha2" /root/axis162-run.log | head -3
curl -s http://127.0.0.1:8080/axis2/services/Version
实测回显:
[INFO] Deploying module: sandesha2-1.6.2 - file:/opt/axis2-1.6.2/repository/modules/sandesha2-1.6.2.mar
<ns:getVersionResponse xmlns:ns="http://axisversion.sample"><ns:return>Hi - the Axis2 version is 1.6.2</ns:return></ns:getVersionResponse>
Deploying module: sandesha2-1.6.2 且无后续异常栈,说明模块加载成功。
4.3 部署 RM 示例服务(RMSampleService)
1)从示例源码包取出服务端类 RMSampleService.java(其中 echoString 按 Sequence 键累积拼接文本,可用于直观验证消息顺序与完整性):
mkdir -p /root/rmdemo/srcroot && cd /root/rmdemo/srcroot
unzip -oq /root/dl/sandesha2-samples-1.6.2-sources.jar
cp sandesha2/samples/userguide/RMSampleService.java .
服务核心逻辑节选(echoString 方法,原样转录自示例源码):
public OMElement echoString(OMElement in) throws Exception {
OMElement textElem = in.getFirstChildWithName(new QName (applicationNamespaceName,Text));
OMElement sequenceElem = in.getFirstChildWithName(new QName (applicationNamespaceName,Sequence));
String textStr = textElem.getText();
String sequenceStr = sequenceElem.getText();
System.out.println("'EchoString' service got text '" + textStr + "' for the sequence '" + sequenceStr + "'");
String previousText = (String) sequenceStrings.get(sequenceStr);
String resultText = (previousText==null)?textStr:previousText+textStr;
sequenceStrings.put(sequenceStr,resultText);
...
return echoStringResponseElem;
}
2)编写 services.xml(保存到 /root/rmdemo/aarbuild/META-INF/services.xml)。actionMapping 必须与客户端 action urn:wsrm:EchoString 一致,否则服务端回 ActionNotSupported(这是实测踩到的第一个坑):
<service name="RMSampleService">
<description>
Sample Service used in the sandesha2 userguide.
</description>
<parameter name="ServiceClass" locked="false">sandesha2.samples.userguide.RMSampleService</parameter>
<operation name="echoString">
<actionMapping>urn:wsrm:EchoString</actionMapping>
<messageReceiver class="org.apache.axis2.receivers.RawXMLINOutMessageReceiver"/>
</operation>
<operation name="ping">
<actionMapping>urn:wsrm:Ping</actionMapping>
<messageReceiver class="org.apache.axis2.receivers.RawXMLINOnlyMessageReceiver"/>
</operation>
<module ref="sandesha2"/>
<module ref="addressing"/>
</service>
逐项说明:ServiceClass 指向实现类;echoString 用 RawXMLINOutMessageReceiver(IN-OUT 原始 XML 收发器);<module ref="sandesha2"/> 与 <module ref="addressing"/> 让服务强制启用 RM 与寻址模块;actionMapping 把 SOAP Action 映射到该操作。
3)用 JDK 8 编译并打 aar:
export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64
export PATH=$JAVA_HOME/bin:$PATH
CP=$(ls /opt/axis2-1.6.2/lib/*.jar | tr '\n' ':')
cd /root/rmdemo
javac -cp "$CP" -d classes RMSampleService.java
mkdir -p aarbuild/sandesha2/samples/userguide
cp classes/sandesha2/samples/userguide/RMSampleService.class aarbuild/sandesha2/samples/userguide/
cd aarbuild
jar cf /root/rmdemo/RMSampleService.aar .
cp /root/rmdemo/RMSampleService.aar /opt/axis2-1.6.2/repository/services/
⚠️ 注意:javac 必须来自 JDK 8。实测曾用 PATH 中默认的 JDK 17 编译,部署时报
UnsupportedClassVersionError: ... class file version 61.0, this version of the Java Runtime only recognizes class file versions up to 52.0(61.0=JDK17 编译产物,52.0=JDK8 运行时上限)。
4)等待热部署(默认约 10~15 秒)并验证:
sleep 15
curl -s http://127.0.0.1:8080/axis2/services/ | head -c 900
实测回显:
<html><head><title>Axis2: Services</title></head><body><h2>Deployed services</h2><h3><a href="Version?wsdl">Version</a></h3>Available operations <ul><li>getVersion</li></ul><h3><a href="RMSampleService?wsdl">RMSampleService</a></h3>Available operations <ul><li>MTOMPing</li><li>Sandesha2OperationInOut</li><li>Sandesha2OperationOutIn</li><li>Sandesha2OperationOutOnly</li><li>Sandesha2OperationInOnly</li><li>ping</li><li>Sandesha2OperationDuplicateInOut</li><li>echoString</li><li>Sandesha2OperationDuplicateInOnly</li></ul></body></html>
RMSampleService 已出现在 Deployed services,且 engage sandesha2 后自动多出 Sandesha2Operation* 一组虚拟操作(供 MakeConnection/匿名 RM 使用);若无此现象请回查 services.xml 是否含 <module ref="sandesha2"/>。
4.4 搭建 RM 客户端并实测可靠序列
1)建立客户端仓库(客户端也需要 addressing + sandesha2 两个模块):
mkdir -p /root/rmclient/repository/modules
cp /root/dl/sandesha2-1.6.2-patched.mar /root/rmclient/repository/modules/sandesha2-1.6.2.mar
cp /opt/axis2-1.6.2/repository/modules/addressing-1.6.2.mar /root/rmclient/repository/modules/
cp /opt/axis2-1.6.2/conf/axis2.xml /root/rmclient/repository/client_axis2.xml
2)把客户端回调监听端口从 8080 改为 6060。这是同机部署的关键一步:不修改时客户端 listener 与服务端争用 8080,RM 响应会被投递到服务端并报 The service cannot be found for the endpoint reference (EPR) http://<本机IP>:8080/axis2/services/anonService2/(实测报错原文)。修改 client_axis2.xml 中的 HTTP transportReceiver 端口:
<transportReceiver name="http"
class="org.apache.axis2.transport.http.SimpleHTTPServer">
<parameter name="port">6060</parameter>
3)取出客户端示例 SyncEchoClient.java、TestCallback.java,把目标端口从 8070 改为 8080 后编译(注意保留源码包路径 sandesha2/samples/userguide):
cd /root/rmclient
unzip -oq /root/dl/sandesha2-samples-1.6.2-sources.jar -d src-extract
mkdir -p src
cp src-extract/sandesha2/samples/userguide/SyncEchoClient.java src/
cp src-extract/sandesha2/samples/userguide/TestCallback.java src/
sed -i 's/private String toPort = "8070";/private String toPort = "8080";/' src/SyncEchoClient.java
export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64
export PATH=$JAVA_HOME/bin:$PATH
CP=$(ls /opt/axis2-1.6.2/lib/*.jar | tr '\n' ':')/root/rmclient/repository/modules/sandesha2-1.6.2.mar
javac -cp "$CP" -d classes src/*.java
客户端要点(SyncEchoClient 原样逻辑):创建 ConfigurationContext 后 engageModule sandesha2,通过 SandeshaClientConstants.SEQUENCE_KEY 把三条 echo 消息编入同一序列,最后一条设置 LAST_MESSAGE:
clientOptions.setProperty(SandeshaClientConstants.SEQUENCE_KEY, sequenceKey);
clientOptions.setTransportInProtocol(Constants.TRANSPORT_HTTP);
clientOptions.setUseSeparateListener(true);
clientOptions.setAction("urn:wsrm:EchoString");
...
clientOptions.setProperty(SandeshaClientConstants.LAST_MESSAGE, "true");
4)运行客户端(仓库路径末尾必须带斜杠:示例源码用 AXIS2_CLIENT_PATH + "client_axis2.xml" 拼接,不带斜杠会报 System can not find the given axis2.xml /root/rmclient/repositoryclient_axis2.xml,实测踩坑):
CP=$(ls /opt/axis2-1.6.2/lib/*.jar | tr '\n' ':')/root/rmclient/repository/modules/sandesha2-1.6.2.mar:/root/rmclient/classes
timeout 100 java -cp "$CP" sandesha2.samples.userguide.SyncEchoClient /root/rmclient/repository/
实测回显:
Callback 'Callback 1' got result:echo1
Callback 'Callback 2' got result:echo1echo2
Callback 'Callback 3' got result:echo1echo2echo3
[SimpleHTTPServer] Stop called
三个回调依次返回 echo1、echo1echo2、echo1echo2echo3——服务端对同一序列 sequence3 的三条消息按序累积拼接,证明三条消息经 RM 序列有序送达且无一丢失。服务端日志同步印证(tail 节选):
'EchoString' service got text 'echo1' for the sequence 'sequence3'
'EchoString' service got text 'echo2' for the sequence 'sequence3'
'EchoString' service got text 'echo3' for the sequence 'sequence3'
💡 说明:
SyncEchoClient的 main 以while (!callback3.isComplete())等待结束,实测中该标志依赖底层 onComplete 事件,典型表现是结果全部打印后进程仍需timeout兜底结束——这是示例代码的固有行为,不影响 RM 结果正确性;生产代码建议用SandeshaClient.waitUntilSequenceCompleted等受控等待。
五、注意事项与兼容性实测
5.1 Axis2 1.6.2 启动脚本的 JDK 坑
Axis2 1.6.2 的 bin/axis2server.sh 以裸命令 java 启动(而非 $JAVA_HOME/bin/java),并附加 -Djava.endorsed.dirs=...。当系统默认 java 指向 JDK 17 时实测报错:
-Djava.endorsed.dirs=/opt/axis2-1.6.2/lib/endorsed:/usr/lib/jvm/java-8-openjdk-amd64/jre/lib/endorsed:/usr/lib/jvm/java-8-openjdk-amd64/lib/endorsed is not supported. Endorsed standards and standalone APIs
in modular form will be supported via the concept of upgradeable modules.
Error: Could not create the Java Virtual Machine.
Error: A fatal exception has occurred. Program will exit.
解决:启动前 export PATH=$JAVA_HOME/bin:$PATH(JAVA_HOME 指 JDK 8),使脚本解析到 JDK 8 的 java。
5.2 与 Axis2 1.8.x 的兼容性断裂(如实实测记录)
在同一台服务器上对 Axis2 1.8.2(OpenJDK 17)做对照实验:放入同一个 sandesha2 mar 后启动。1.8.2 官方 axis2server.sh 还存在脚本自身缺陷——引用的启动类 org.apache.axis2.transport.SimpleAxis2Server 在 1.8.2 中已迁移,实测报:
Error: Could not find or load main class org.apache.axis2.transport.SimpleAxis2Server
Caused by: java.lang.ClassNotFoundException: org.apache.axis2.transport.SimpleAxis2Server
改用 1.8.2 jar 内实际存在的类 org.apache.axis2.kernel.SimpleAxis2Server 手工启动后,sandesha2 模块部署仍然失败(服务端日志原文):
[ERROR] The sandesha2-1.6.2.mar module, which is not valid, caused Can't find resource for bundle org.apache.axis2.i18n.ProjectResourceBundle, key Processing Operations Modules with an error of An unsupported message exchange pattern (MEP) exists in ID is http://www.w3.org/2006/01/wsdl/in-only.
org.apache.axis2.deployment.DeploymentException: Can't find resource for bundle org.apache.axis2.i18n.ProjectResourceBundle, key Processing Operations Modules with an error of An unsupported message exchange pattern (MEP) exists in ID is http://www.w3.org/2006/01/wsdl/in-only.
at org.apache.axis2.deployment.repository.util.ArchiveReader.readModuleArchive(ArchiveReader.java:564) ~[axis2-kernel-1.8.2.jar:1.8.2]
即 Sandesha2 1.6.2 的 module.xml 使用的 MEP URI(WS-Addressing 2006/01 WSDL 命名空间的 in-only)在 Axis2 1.8.x 中不被支持,模块加载失败、RM 能力不可用。结论:Axis2 1.8.x 与 Sandesha2 1.6.2 的兼容性断裂是确定性的,且官方无修复版本,集成路径只有降级到 Axis2 1.6.x。
5.3 其他注意事项
client_axis2.xml必须放在客户端仓库根目录(与modules/平级),示例源码按repo路径 + "client_axis2.xml"拼接读取;- 服务端与客户端同机时,客户端回调端口必须错开(本文 6060),多客户端可在 6061、6062 依次排开,每客户端一份仓库目录;
- 模块与服务 aar 放入
repository/后由 Axis2 热部署扫描加载,替换文件后建议先删除旧 aar 再放入新 aar,避免坏包缓存; - Sandesha2 默认序列状态存内存,服务端重启序列即失效,可靠性验证需在同一进程生命周期内完成。
六、参考链接
- Axis2 发行归档(本文下载源):https://archive.apache.org/dist/axis/axis2/java/core/
- Sandesha2 Maven Central 模块包:https://repo1.maven.org/maven2/org/apache/sandesha2/sandesha2/
- Sandesha2 Maven Central 示例源码:https://repo1.maven.org/maven2/org/apache/sandesha2/sandesha2-samples/
- 平台同系列文档:《Apache Sandesha2 介绍与选型指南》《Apache Sandesha2 配置参数详解》