Apache Axis2 快速入门与集成示例

以 Axis2 2.0.1 实测跑通服务全链路:javac -g 编译 POJO、aar 发布与热部署、SOAP 调用、stub 生成、Maven 与 TCP 客户端调用,均附真实回显。

Apache Axis2Axis22026/10/13

Apache Axis2 快速入门与集成示例

目标:从一个纯 Java 类出发,跑通 Axis2 服务端到客户端的完整链路——编写并编译 POJO 服务、打包 .aar 发布与热部署验证、curl 直接发送 SOAP 调用、wsdl2java 生成客户端 stub 直跑、Maven 工程集成、TCP 传输调用——每一步均附真实命令与回显,已在 Ubuntu 22.04.5(OpenJDK 17.0.20.1、Axis2 2.0.1 standalone)实测通过。

一、环境信息

本篇全部命令与回显均在以下环境中实测采集:

  • 操作系统:Ubuntu 22.04.5 LTS,x86_64
  • JDK:OpenJDK 17.0.20.1(JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64)
  • 组件版本:Apache Axis2 2.0.1(官方 bin 发行包,standalone 形态)
  • 安装目录:/opt/axis2(服务仓库 /opt/axis2/repository/services,配置 /opt/axis2/conf/axis2.xml)
  • 服务端口:HTTP 8080、TCP 6060(第七节开启)
  • 客户端构建:Apache Maven 3.6.3
  • 示例工程目录:/opt/lab/hello-service(服务端)、/opt/lab/hello-maven(Maven 客户端)、/opt/lab/client-repo(TCP 客户端仓库)
  • 执行用户:root

二、前置条件

按《Ubuntu 22.04 安装 Apache Axis2 指南》或《CentOS 8 安装 Apache Axis2 指南》完成 Axis2 2.0.1 standalone 安装,并确认基线服务可调用:

export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64
export PATH=$JAVA_HOME/bin:$PATH
curl -s "http://localhost:8080/axis2/services/Version/getVersion"

回显(实测):

<ns:getVersionResponse xmlns:ns="http://axisversion.sample"><ns:return>Hi - the Axis2 version is 2.0.1</ns:return></ns:getVersionResponse>

Maven 客户端一节另需 Maven(Ubuntu 用 apt install maven 即可,实测版本 3.6.3)。

三、发布第一个 POJO 服务

3.1 编写并编译服务类

Axis2 服务就是一个普通 Java 类(POJO),公开方法即服务操作。创建工程目录并编写服务类:

mkdir -p /opt/lab/hello-service/src /opt/lab/hello-service/build/HelloService/META-INF
cat > /opt/lab/hello-service/src/HelloService.java <<'EOF'
public class HelloService {
    public String sayHello(String name) {
        return "Hello, " + name + "! (from Axis2 " + org.apache.axis2.Version.getVersionText() + ")";
    }
    public String echo(String msg) {
        return "echo: " + msg;
    }
}
EOF

编译(-g 保留形参名,是本篇最关键的一个编译参数):

javac -version && javac -g -cp "/opt/axis2/lib/*" -d /opt/lab/hello-service/build/HelloService /opt/lab/hello-service/src/HelloService.java

回显(实测,编译成功无输出):

javac 17.0.20.1

-cp "/opt/axis2/lib/*" 用于解析源码里引用的 org.apache.axis2.Version(服务端 lib 下的 axis2-kernel jar 提供)。-g 的作用:Axis2 反射生成 WSDL 时用形参名作为请求元素名,缺省编译(无 -g)时形参名丢失,WSDL 参数会退化成 args0,客户端 stub 的 setter 也随之变成 setArgs0——两种编译方式的 stub 代码差异实测确认过(setName 与 setArgs0)。

3.2 编写 services.xml 并打包 .aar

服务级描述文件声明服务名、实现类与消息接收器:

cat > /opt/lab/hello-service/build/HelloService/META-INF/services.xml <<'EOF'
<service name="HelloService" scope="application">
    <description>POJO demo service</description>
    <parameter name="ServiceClass">HelloService</parameter>
    <transports>
        <transport>http</transport>
        <transport>tcp</transport>
    </transports>
    <operation name="sayHello">
        <messageReceiver class="org.apache.axis2.rpc.receivers.RPCMessageReceiver"/>
    </operation>
    <operation name="echo">
        <messageReceiver class="org.apache.axis2.rpc.receivers.RPCMessageReceiver"/>
    </operation>
</service>
EOF

把类与描述文件打成 .aar 包并直接放入服务仓库:

cd /opt/lab/hello-service/build/HelloService && jar cf /opt/axis2/repository/services/HelloService.aar HelloService.class META-INF/
jar tf /opt/axis2/repository/services/HelloService.aar

回显(实测):

META-INF/
META-INF/MANIFEST.MF
HelloService.class
META-INF/services.xml

.aar 的最小结构就是"编译产物 + META-INF/services.xml"(MANIFEST.MF 由 jar 命令自动生成)。<transports> 声明服务可经 HTTP 与 TCP 访问——只走 HTTP 时省略亦可,但第七节要走 TCP,这里一并声明,避免服务对 TCP 传输不可用。

3.3 部署验证与热部署行为

3.2 节打包时已直接写入仓库。 Axis2 默认 hotdeployment=true,新 .aar 落入仓库后由后台线程自动部署(systemd 托管时用 journalctl 观察日志):

journalctl -u axis2 --no-pager --since "2 minutes ago" | grep "Deploying Web service"

回显(实测):

10:05:50.925 [main] INFO  org.apache.axis2.deployment.DeploymentEngine - Deploying Web service: HelloService.aar - file:/opt/axis2/repository/services/HelloService.aar

热部署对"新增"生效,对"更新"受 hotupdate=false(默认)限制——实测:覆盖同名 .aar 后服务不重新加载,须重启进程才生效。热卸载/重部署的完整行为实测(删除 .aar 约一个轮询周期后被卸载,放回后再被部署):

rm /opt/axis2/repository/services/HelloService.aar && sleep 12 && cp /tmp/HelloService.aar /opt/axis2/repository/services/HelloService.aar && sleep 12 && journalctl -u axis2 --no-pager --since "1 minute ago" | grep -E "Undeploying|Deploying Web service"

回显(实测):

10:08:10.931 [Timer-0] INFO  org.apache.axis2.deployment.ServiceDeployer - Undeploying Web service: HelloService
10:08:20.935 [Timer-0] INFO  org.apache.axis2.deployment.DeploymentEngine - Deploying Web service: HelloService.aar - file:/opt/axis2/repository/services/HelloService.aar

两行日志都出自 Timer-0 线程,间隔即热部署轮询周期(约 10 秒)。验证服务就绪后即可进入调用环节。

四、SOAP 调用验证

4.1 curl 直接发送 SOAP 信封

用 curl 构造 SOAP 1.1 请求调用 sayHello(namespace 与 operation 元素名来自服务的 WSDL):

curl -s -H "Content-Type: text/xml" -H "SOAPAction: urn:sayHello" -d '<?xml version="1.0" encoding="UTF-8"?><soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"><soapenv:Body><sayHello xmlns="http://ws.apache.org/axis2"><name>Alice</name></sayHello></soapenv:Body></soapenv:Envelope>' http://localhost:8080/axis2/services/HelloService

回显(实测):

<?xml version="1.0" encoding="UTF-8"?><soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"><soapenv:Header/><soapenv:Body><ns:sayHelloResponse xmlns:ns="http://ws.apache.org/axis2"><ns:return>Hello, Alice! (from Axis2 2.0.1)</ns:return></ns:sayHelloResponse></soapenv:Body></soapenv:Envelope>

echo 操作同理:

curl -s -H "Content-Type: text/xml" -H "SOAPAction: urn:echo" -d '<?xml version="1.0" encoding="UTF-8"?><soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"><soapenv:Body><echo xmlns="http://ws.apache.org/axis2"><msg>axis2-test-2026</msg></echo></soapenv:Body></soapenv:Envelope>' http://localhost:8080/axis2/services/HelloService

回显(实测):

<?xml version="1.0" encoding="UTF-8"?><soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"><soapenv:Header/><soapenv:Body><ns:echoResponse xmlns:ns="http://ws.apache.org/axis2"><ns:return>echo: axis2-test-2026</ns:return></ns:echoResponse></soapenv:Body></soapenv:Envelope>

回显里的 <ns:return> 即方法返回值,xmlns:ns="http://ws.apache.org/axis2" 是默认 targetNamespace。

4.2 REST GET 形态

Axis2 支持 HTTP GET 直调(参数放查询串):

curl -s "http://localhost:8080/axis2/services/HelloService/sayHello?name=Alice"

回显(实测):

<ns:sayHelloResponse xmlns:ns="http://ws.apache.org/axis2"><ns:return>Hello, Alice! (from Axis2 2.0.1)</ns:return></ns:sayHelloResponse>

该形态的参数绑定依赖形参名(元素名 <name> 与方法形参一致),因此同样要求 3.1 节的 -g 编译;查询串参数名与元素名不一致时参数绑定为 null。生产集成建议统一走 4.1 节的标准 SOAP,GET 形态适合快速冒烟。

五、零 Maven 直跑客户端

不引入构建工具,用 wsdl2java 生成 stub 后以 javac/java 直接编译运行——这也是理解 stub 依赖构成的最小方式。

5.1 生成 stub

rm -rf /opt/lab/hello-client
/opt/axis2/bin/wsdl2java.sh -uri http://localhost:8080/axis2/services/HelloService?wsdl -p demo.client -o /opt/lab/hello-client

回显(实测,省略日志噪音行):

Retrieving document at 'http://localhost:8080/axis2/services/HelloService?wsdl'.

生成的文件与结构见《Apache Axis2 常用 CLI 命令与工具详解》6.2 节(HelloServiceStub.java / HelloServiceCallbackHandler.java / build.xml)。stub 的方法名、请求类名与 setter 都由 WSDL 推导——这是 3.1 节强调 -g 的原因。

5.2 编写调用主类

mkdir -p /opt/lab/hello-client/src/demo/client
cat > /opt/lab/hello-client/src/demo/client/HelloClient.java <<'EOF'
package demo.client;

public class HelloClient {
    public static void main(String[] args) throws Exception {
        HelloServiceStub stub = new HelloServiceStub(
                "http://localhost:8080/axis2/services/HelloService");
        HelloServiceStub.SayHello req = new HelloServiceStub.SayHello();
        req.setName("Alice");
        System.out.println("sayHello => " + stub.sayHello(req).get_return());
        HelloServiceStub.Echo req2 = new HelloServiceStub.Echo();
        req2.setMsg("axis2-maven-client-2026");
        System.out.println("echo     => " + stub.echo(req2).get_return());
    }
}
EOF

5.3 编译与运行

cd /opt/lab/hello-client && mkdir -p classes && javac -cp "/opt/axis2/lib/*" -d classes src/demo/client/*.java && java -cp "classes:/opt/axis2/lib/*" demo.client.HelloClient

回显(实测):

Note: src/demo/client/HelloServiceStub.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
SLF4J(W): No SLF4J providers were found.
SLF4J(W): Defaulting to no-operation (NOP) logger implementation
SLF4J(W): See https://www.slf4j.org/codes.html#noProviders for further details.
sayHello => Hello, Alice! (from Axis2 2.0.1)
echo     => echo: axis2-maven-client-2026

结果与 4.1 节 curl 完全一致。Note 两行是 stub 内部集合用法的编译提示,SLF4J(W) 三行是未接入日志实现时的提示,均不影响调用。若 javac 报 class file has wrong version 61.0, should be 52.0,说明当前 javac 是 JDK 8(Axis2 2.0.1 的 jar 是 Java 17 字节码),用 export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64 && export PATH=$JAVA_HOME/bin:$PATH 切换后重试(Ubuntu 上 java 与 javac 的 alternatives 指向可能不同步,实测踩过)。

六、Maven 客户端集成

6.1 依赖声明

创建工程并声明 Axis2 客户端最小依赖集(五个构件、版本统一 2.0.1):

mkdir -p /opt/lab/hello-maven/src/main/java/demo/client
cat > /opt/lab/hello-maven/pom.xml <<'EOF'
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>demo</groupId>
    <artifactId>hello-maven-client</artifactId>
    <version>1.0.0</version>
    <packaging>jar</packaging>
    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.apache.axis2</groupId>
            <artifactId>axis2-kernel</artifactId>
            <version>2.0.1</version>
        </dependency>
        <dependency>
            <groupId>org.apache.axis2</groupId>
            <artifactId>axis2-adb</artifactId>
            <version>2.0.1</version>
        </dependency>
        <dependency>
            <groupId>org.apache.axis2</groupId>
            <artifactId>axis2-transport-http</artifactId>
            <version>2.0.1</version>
        </dependency>
        <dependency>
            <groupId>org.apache.axis2</groupId>
            <artifactId>axis2-transport-tcp</artifactId>
            <version>2.0.1</version>
        </dependency>
        <dependency>
            <groupId>org.apache.axis2</groupId>
            <artifactId>axis2-transport-local</artifactId>
            <version>2.0.1</version>
        </dependency>
    </dependencies>
</project>
EOF

五个依赖的分工:kernel 是核心(Options/ServiceClient/stub 基类);adb 是数据绑定(stub 反序列化);三个 transport 分别覆盖 HTTP、TCP 与本地(JVM 内直调,测试用)。实测缺 transport-local 时启动报 LocalTransportSender ClassNotFound——stub 初始化会装配全部已声明传输的发送器。

6.2 客户端主类

把 5.2 节的 HelloClient.java 复制进 Maven 源码目录(stub 源码同样需要):

cp /opt/lab/hello-client/src/demo/client/HelloClient.java /opt/lab/hello-maven/src/main/java/demo/client/
cp /opt/lab/hello-client/src/demo/client/HelloServiceStub.java /opt/lab/hello-maven/src/main/java/demo/client/
cp /opt/lab/hello-client/src/demo/client/HelloServiceCallbackHandler.java /opt/lab/hello-maven/src/main/java/demo/client/

6.3 编译运行

cd /opt/lab/hello-maven && mvn -q compile exec:java -Dexec.mainClass=demo.client.HelloClient 2>&1 | grep -v "^\["

回显(实测):

SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
sayHello => Hello, Alice! (from Axis2 2.0.1)
echo     => echo: axis2-maven-client-2026

与 5.3 节直跑结果一致,验证两种构建方式等价。SLF4J 三行提示源于 classpath 无日志实现,加入 slf4j-simple 之类绑定即可消除,不影响功能。

七、TCP 传输客户端

Axis2 除 HTTP 外原生支持 TCP 传输(SOAP 报文直接走 TCP 流,无 HTTP 头开销)。本节把调用从 8080/HTTP 切到 6060/TCP。

7.1 服务端开启 TCP 监听

编辑 /opt/axis2/conf/axis2.xml,在 HTTP transportReceiver 之后加入 TCP 接收器(参数名是 transport.tcp.port,不是 port——实测用错参数名时 6060 根本不监听):

<transportReceiver name="tcp"
                   class="org.apache.axis2.transport.tcp.TCPTransportListener">
    <parameter name="transport.tcp.port">6060</parameter>
</transportReceiver>

TCP 发送器 Axis2 已内置,确认存在即可:

grep -n 'transportSender name="tcp"' /opt/axis2/conf/axis2.xml

回显(实测):

    <transportSender name="tcp"

修改配置后重启进程生效(systemd 托管环境 systemctl restart axis2),确认端口监听与启动日志:

journalctl -u axis2 --no-pager --since "1 minute ago" | grep "TCP server"

回显(实测):

09:59:52.071 [main] INFO  org.apache.axis2.transport.tcp.TCPServer - TCP server started on port : 6060

同时确认 3.2 节 services.xml 的 <transports> 已声明 tcp(未声明的服务对 TCP 传输不可用,实测会打 WARN 且调用失败)。

7.2 准备客户端仓库

客户端需要一个独立 ConfigurationContext 仓库:放 addressing 模块、复制服务端 axis2.xml 后删掉全部 transportReceiver 段(客户端只发送不监听):

mkdir -p /opt/lab/client-repo/conf /opt/lab/client-repo/modules
cp /opt/axis2/repository/modules/addressing-2.0.1.mar /opt/lab/client-repo/modules/
cp /opt/axis2/conf/axis2.xml /opt/lab/client-repo/conf/axis2.xml

用编辑器删除 /opt/lab/client-repo/conf/axis2.xml 中所有 <transportReceiver ...>...</transportReceiver> 段(HTTP 与 TCP 两处),transportSender 段全部保留。最终结构:

find /opt/lab/client-repo -type f

回显(实测):

/opt/lab/client-repo/conf/axis2.xml
/opt/lab/client-repo/modules/addressing-2.0.1.mar

7.3 TCP 客户端代码

stub 复用 5.1 节生成物,差异只在三点:EPR 协议改为 tcp://、指定传输协议为 TCP、把 SOAP 版本显式设为 1.1:

cat > /opt/lab/hello-maven/src/main/java/demo/client/TcpHelloClient.java <<'EOF'
package demo.client;

import org.apache.axis2.Constants;
import org.apache.axis2.addressing.EndpointReference;
import org.apache.axis2.client.Options;
import org.apache.axis2.context.ConfigurationContext;
import org.apache.axis2.context.ConfigurationContextFactory;
import org.apache.axiom.soap.SOAP11Constants;

public class TcpHelloClient {
    public static void main(String[] args) throws Exception {
        ConfigurationContext cc = ConfigurationContextFactory.createConfigurationContextFromFileSystem(
                "/opt/lab/client-repo", "/opt/lab/client-repo/conf/axis2.xml");
        HelloServiceStub stub = new HelloServiceStub(cc,
                "tcp://localhost:6060/axis2/services/HelloService");
        Options options = stub._getServiceClient().getOptions();
        options.setTransportInProtocol(Constants.TRANSPORT_TCP);
        options.setSoapVersionURI(SOAP11Constants.SOAP_ENVELOPE_NAMESPACE_URI);
        options.setAction("urn:sayHello");
        HelloServiceStub.SayHello req = new HelloServiceStub.SayHello();
        req.setName("Bob");
        System.out.println("tcp sayHello => " + stub.sayHello(req).get_return());
    }
}
EOF

7.4 运行

cd /opt/lab/hello-maven && mvn -q compile exec:java -Dexec.mainClass=demo.client.TcpHelloClient 2>&1 | grep -v "^\["

回显(实测):

SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
tcp sayHello => Hello, Bob! (from Axis2 2.0.1)

TCP 链路调用成功。其中 SOAP 版本一行不能省:TCP 传输默认按 SOAP 1.1(contentType text/xml)解析入站报文,而 stub 默认发送 SOAP 1.2,两端不匹配时服务端报 Transport level information does not match with SOAP Message namespace URI(实测复现过);setSoapVersionURI(SOAP11Constants.SOAP_ENVELOPE_NAMESPACE_URI) 把请求对齐到 1.1 后链路打通。若确需 SOAP 1.2 走 TCP,服务端 axis2.xml 的 TCP 接收器还需加 <parameter name="transport.tcp.contentType">application/soap+xml</parameter>(实测仅改客户端 contentType 无法通过)。

八、注意事项

  • 服务类必须 javac -g 编译:缺 -g 时 WSDL 参数退化为 args0,stub setter 变 setArgs0,4.2 节 GET 形态参数也无法绑定(两种行为均实测确认)。
  • 修改服务类重打包后:新增 .aar 热部署生效(约 10 秒轮询,Timer 线程日志);覆盖同名 .aar 不生效(hotupdate 默认 false),须重启进程。
  • 更新服务后要重新执行 wsdl2java 生成 stub——stub 是按旧 WSDL 推导的静态代码,服务签名变了 stub 不同步。
  • 编译客户端时 javac 版本必须 ≥17(Axis2 2.0.1 为 61.0 字节码);Ubuntu 下 java 与 javac 的 alternatives 指向可能不同步,报 wrong version 61.0, should be 52.0 时先检查 javac -version。
  • TCP 接收器参数名是 transport.tcp.port;裸 port 参数实测不生效(6060 不监听)。services.xml 需 <transports> 声明 tcp,否则服务对 TCP 不可用。
  • TCP 调用必须 setSoapVersionURI 对齐 SOAP 1.1,否则报 "Transport level information does not match with SOAP Message namespace URI"。
  • Maven 客户端五个依赖缺一不可,缺 transport-local 时启动即报 LocalTransportSender ClassNotFound。
  • 裸 GET 服务 URL(如 /axis2/services/HelloService 不带操作)返回 500 与 "Operation not found" fault 是正常行为,不代表服务故障;判活用 Version 服务或带操作的调用。

九、参考链接

  1. Apache Axis2 官方主页(用户指南):https://axis.apache.org/axis2/java/core/
  2. Axis2 快速入门(官方 Quick Start):https://axis.apache.org/axis2/java/core/docs/quickstartguide.html
  3. pojo 服务与 SOAP 相关配置说明(官方用户指南服务章节):https://axis.apache.org/axis2/java/core/docs/userguide.html
  4. TCP 传输模块说明(Axis2 传输栈):https://axis.apache.org/axis2/java/core/docs/transport_howto.html
  5. Apache Axis2 版本下载目录(本篇实测版本 2.0.1):https://dlcdn.apache.org/axis/axis2/java/core/