☰
Apache Axis1.4 官网备份:老系统 SOAP WebService 接口对接与部署实战
2026/10/14 10:04:53 网站建设 项目流程

简介:Apache Axis1.4 官网备份是一份面向 Java Web 服务开发者与教学研究者的历史版本资源包,用于在官方停止维护后仍能搭建 SOAP 服务端与客户端环境,适合需要复现早期 JAX-RPC、WSDL 自动代码生成等经典技术栈的中高级开发者。压缩包共 187 个文件,约 3.07MB,以 161 个 class 字节码和 12 个 jar 依赖库为主体,辅以 4 个 jsp 页面、3 个 jws 服务脚本及 properties、xml、java 等配置与源码文件,基本覆盖 Axis 运行所需的类库、示例服务与部署描述。资源已有 215 人学习下载,可帮助读者直接获得可运行的 Axis1.4 环境,对照 InteropTest、AddressBook、StarWars 等示例理解 SOAP 绑定、附件传输与互操作性测试的实现方式,并借助 jar 与 class 结构梳理 Axis 的模块划分,为研究早期 Web 服务框架或维护遗留系统提供参考。

1. 从一次老系统联调说起:为什么我还在翻 Axis1.4 的官网备份

上周帮一个做政务系统的朋友排查接口问题,对方甩过来一个.jws文件,说服务端是十几年前搭的,现在要对接新平台,结果新同事连怎么调通都不知道。我一看那堆deploy.wsdd、server-config.wsdd的配置,心里就有数了——这是 Apache Axis1.4 的活儿。这玩意儿在 2006 年就停止维护了,但国内大量老系统、老项目还在跑,尤其是那些基于 SOAP 的 WebService 接口,Axis1.4 几乎是绕不开的存在。问题是,官网早就归档了,下载链接要么失效,要么被重定向到一堆无关页面,想找一份干净的安装包和文档,得翻半天。我手里这份官网备份,就是当年从归档站扒下来的完整资源,包含二进制包、源码包、文档和依赖库。它解决的不是什么高深技术问题,就是让还在维护老系统的工程师能快速拿到可用的工具,不用在搜索引擎里大海捞针。如果你正在对接老接口、维护遗留系统,或者单纯想搞清楚 SOAP 引擎到底怎么跑起来的,这份东西值得备一份。

2. Axis1.4 的运行时结构:从 SOAP 引擎到部署描述符

2.1 核心组件与请求处理链路

Axis1.4 本质上是一个 SOAP 引擎,它把 HTTP 请求里的 XML 报文解析成 Java 对象,再调用对应的服务方法,最后把返回值序列化回 XML。整个链路的核心组件包括AxisServlet、AxisEngine、MessageContext和Handler链。AxisServlet负责接收 HTTP 请求,AxisEngine驱动整个处理流程,MessageContext贯穿始终,存储请求和响应数据,而Handler链则按顺序执行认证、日志、序列化等操作。理解这条链路,对排查“为什么请求到了服务端却没反应”这类问题至关重要。常见做法是先在server-config.wsdd里把<requestFlow>和<responseFlow>的 Handler 顺序看清楚,再结合日志定位卡在哪一环。

2.2 部署描述符的两种写法

Axis1.4 支持两种部署方式:一种是即时部署(JWS),直接把.java文件改名为.jws丢到 Web 应用目录下,Axis 会自动编译并暴露服务;另一种是定制部署(WSDD),通过deploy.wsdd文件精确控制服务名、类名、作用域和 Handler 链。JWS 适合快速验证,但生产环境一般用 WSDD,因为可以配置scope(Request、Session、Application)、provider(java:RPC、java:MSG)和类型映射。我一般会先写一个最小的deploy.wsdd,只配服务名和类名,跑通后再逐步加 Handler 和类型映射,避免一上来就被复杂的配置劝退。

<!-- deploy.wsdd 最小可用示例 --> <deployment xmlns="http://xml.apache.org/axis/wsdd/" xmlns:java="http://xml.apache.org/axis/wsdd/providers/java"> <!-- 服务名对外暴露,类名指向实际实现 --> <service name="HelloService" provider="java:RPC"> <!-- 允许调用的方法,* 表示全部 --> <parameter name="allowedMethods" value="*"/> <!-- 指定服务实现类 --> <parameter name="className" value="com.example.HelloService"/> <!-- 作用域:Request 每次请求新建实例 --> <parameter name="scope" value="Request"/> </service> </deployment>

上面这段配置里,name是客户端调用时用的服务名,className必须写全限定名,allowedMethods控制暴露哪些方法,生产环境不建议用*,而是显式列出方法名。scope设为Request时,每次请求都会创建新的服务实例,适合无状态服务;如果服务需要维持状态,可以改成Session或Application,但要小心线程安全问题。部署时用java -cp axis.jar org.apache.axis.client.AdminClient deploy.wsdd命令推送到服务端,成功后会返回Done processing。

2.3 客户端调用的三种姿势

客户端调用 Axis1.4 服务,常见的有三种方式:动态调用接口(DII)、存根(Stub)和动态代理。DII 最灵活,不需要生成任何代码,直接拼Call对象就能调;Stub 是先用WSDL2Java生成一堆类,然后像调本地方法一样调远程服务;动态代理则是用Service和Call的组合,介于两者之间。我一般排查问题时先用 DII 快速验证服务端是否正常,确认后再用 Stub 集成到业务代码里。

// DII 方式调用 HelloService 的 sayHello 方法 import org.apache.axis.client.Call; import org.apache.axis.client.Service; import javax.xml.namespace.QName; public class DiiClient { public static void main(String[] args) throws Exception { // 服务端地址,注意替换成实际 IP 和端口 String endpoint = "http://localhost:8080/axis/services/HelloService"; Service service = new Service(); Call call = (Call) service.createCall(); call.setTargetEndpointAddress(new java.net.URL(endpoint)); // 设置要调用的方法名和命名空间 call.setOperationName(new QName("http://example.com", "sayHello")); // 传入参数并执行,参数类型是 String String result = (String) call.invoke(new Object[]{"Axis"}); System.out.println("返回结果:" + result); } }

这段代码里,endpoint是服务暴露的 URL,QName的第一个参数是命名空间,必须和服务端 WSDD 里配置的一致,否则会报No such operation。call.invoke的参数数组顺序和类型必须和方法签名匹配,否则会抛AxisFault。如果服务端要求认证,还需要在call上设置SOAPHeader或用户名密码。DII 的好处是改起来快,坏处是类型安全全靠手动保证,容易在参数类型上翻车。

3. 把备份跑起来:从解压到第一个 SOAP 请求

3.1 目录结构与依赖清单

拿到这份官网备份后,先别急着往项目里塞。我一般会先解压到一个干净的目录,看清楚里面有什么。典型的 Axis1.4 二进制包解压后包含lib、webapps、samples和docs四个目录。lib里是核心 jar 包,webapps里是可直接部署的axisWeb 应用,samples里有一些示例代码,docs是 API 文档和用户指南。依赖方面,Axis1.4 需要 JDK 1.4 以上,但实际跑起来建议用 JDK 8,再高的版本可能会遇到javax.xml相关类冲突。另外还需要activation.jar、mail.jar、wsdl4j.jar等,这些在lib目录里都有,不用单独去找。

文件/目录用途注意事项
lib/axis.jar核心引擎必须加入 classpath
lib/wsdl4j.jarWSDL 解析生成 Stub 时需要
lib/activation.jar附件处理处理 MIME 类型时需要
lib/mail.jar邮件传输一般用不到,但缺了会报错
webapps/axis可直接部署的 WAR 目录复制到 Tomcat 的 webapps 下即可
samples示例代码建议先跑通再改

3.2 部署到 Tomcat 的完整步骤

部署 Axis1.4 到 Tomcat 是最常见的用法。先把webapps/axis整个目录复制到 Tomcat 的webapps下,然后启动 Tomcat。访问http://localhost:8080/axis/应该能看到 Axis 的欢迎页面,上面有Validate和List等链接。如果页面报 404,检查 Tomcat 的web.xml里有没有配AxisServlet的映射;如果报 500,多半是lib下的 jar 包没复制全。我遇到过一种情况:Tomcat 9 默认不加载axis目录下的lib,需要把 jar 包放到WEB-INF/lib里,或者修改catalina.properties的common.loader。这一步踩坑的人不少,血泪经验就是先看 Tomcat 日志,别瞎猜。

# 假设 Tomcat 安装在 /opt/tomcat,Axis 备份解压在 /tmp/axis-backup cp -r /tmp/axis-backup/webapps/axis /opt/tomcat/webapps/ # 确保 jar 包在 WEB-INF/lib 下 cp /tmp/axis-backup/lib/*.jar /opt/tomcat/webapps/axis/WEB-INF/lib/ # 重启 Tomcat /opt/tomcat/bin/shutdown.sh /opt/tomcat/bin/startup.sh # 验证服务是否启动 curl http://localhost:8080/axis/

上面这几条命令里,cp -r复制整个 Web 应用目录,cp把依赖 jar 包补到WEB-INF/lib,重启后curl验证。如果curl返回 HTML 页面,说明 Axis 已经跑起来了。接下来可以访问http://localhost:8080/axis/servlet/AxisServlet?list查看已部署的服务列表。如果列表为空,说明还没有部署任何服务,需要写 WSDD 文件并推送。

3.3 用 AdminClient 推送服务并验证

服务端跑起来后,下一步是部署一个实际的服务。假设你已经写好了一个HelloService类,编译后放到WEB-INF/classes下,然后写一个deploy.wsdd,用AdminClient推送。推送成功后,再访问?list应该能看到HelloService。这时候用 DII 客户端调一下,如果返回预期结果,说明整条链路通了。常见问题是AdminClient报Connection refused,多半是 Tomcat 没启动或者端口不对;如果报No such service,检查 WSDD 里的服务名和客户端调用时用的服务名是否一致。

# 推送 WSDD 文件到服务端 java -cp "/tmp/axis-backup/lib/*" org.apache.axis.client.AdminClient \ -l http://localhost:8080/axis/services/AdminService \ deploy.wsdd # 推送成功后,查看服务列表 curl "http://localhost:8080/axis/servlet/AxisServlet?list"

AdminClient的-l参数指定 AdminService 的地址,默认是http://localhost:8080/axis/services/AdminService。如果服务端改了端口或路径,这里要同步改。推送成功后,?list会显示服务名、类型和状态。如果服务状态是Active,说明部署成功;如果是Failed,看 Tomcat 日志里的异常堆栈,通常是类找不到或者方法签名不匹配。

4. 避坑与排查:Axis1.4 那些年我踩过的雷

4.1 现象:客户端报No such operation,服务端日志无异常

原因通常是命名空间不匹配。Axis1.4 默认的命名空间是http://xml.apache.org/axis/wsdd/,但服务端 WSDD 里如果指定了namespace参数,客户端调用时必须用同一个。解决方法是检查 WSDD 里的<parameter name="namespace" value="..."/>,然后在客户端QName里用相同的值。如果 WSDD 没写 namespace,Axis 会用默认的http://tempuri.org/,客户端也要对应。

4.2 现象:部署时报ClassNotFoundException

原因一般是类文件没放到正确的位置。Axis1.4 默认从WEB-INF/classes和WEB-INF/lib加载类,如果类在别的目录,需要在server-config.wsdd里配置classpath或者把类复制过去。另一种可能是 jar 包冲突,比如项目里已经有axis.jar,又放了一份到WEB-INF/lib,导致类加载器加载了旧版本。解决方法是清理重复 jar,确保WEB-INF/lib下只有一份 Axis 相关包。

4.3 现象:SOAP 报文里的中文变成乱码

原因是字符编码不一致。Axis1.4 默认用ISO-8859-1编码,而客户端可能用UTF-8。解决方法是在server-config.wsdd里加<parameter name="axis.encoding" value="UTF-8"/>,或者在客户端Call对象上设置call.setEncodingStyle("UTF-8")。另外,Tomcat 的server.xml里Connector的URIEncoding也要设成UTF-8,否则 URL 里的中文参数会乱码。

4.4 现象:大文件传输时内存溢出

Axis1.4 默认把整个 SOAP 报文加载到内存里,传输大文件时容易 OOM。解决方法是启用附件(Attachment)机制,用AttachmentPart分块传输,或者调整 JVM 的-Xmx参数。但更根本的做法是评估是否真的需要用 SOAP 传大文件,如果只是文件上传下载,用 HTTP 直接传更合适。我一般会建议把大文件走 FTP 或对象存储,SOAP 只传元数据。

4.5 现象:Tomcat 9 下 Axis 页面 404

原因是 Tomcat 9 默认不扫描webapps/axis下的lib目录,需要把 jar 包放到WEB-INF/lib,或者修改conf/catalina.properties里的common.loader加上${catalina.base}/webapps/axis/lib/*.jar。另一个可能是web.xml里的servlet-mapping被覆盖了,检查AxisServlet的映射是否还在。如果用的是 Spring Boot 内嵌 Tomcat,还需要额外配置ServletRegistrationBean。

5. 进阶技巧:用 WSDL2Java 生成 Stub 并集成到项目

5.1 生成 Stub 的完整命令与参数

当你确认服务端没问题后,下一步就是把调用逻辑集成到业务代码里。手写 DII 太累,用WSDL2Java生成 Stub 是更工程化的做法。命令在lib目录下执行,指定 WSDL 的 URL 和输出目录。生成的类包括HelloServiceSoapBindingStub、HelloServiceLocator和一堆序列化类。把这些类复制到项目里,就可以像调本地方法一样调远程服务。

# 生成 Stub 代码,-o 指定输出目录,-p 指定包名 java -cp "/tmp/axis-backup/lib/*" org.apache.axis.wsdl.WSDL2Java \ -o /tmp/generated-src \ -p com.example.stub \ http://localhost:8080/axis/services/HelloService?wsdl

-o是输出目录,-p是生成类的包名,最后的 URL 是 WSDL 地址。如果 WSDL 需要认证,可以加-U和-P参数传用户名密码。生成后,HelloServiceLocator的getHelloService()方法返回一个 Stub 实例,直接调sayHello就行。注意生成的 Stub 默认超时时间可能很短,生产环境要调setTimeout。

5.2 集成到 Spring 项目的注意事项

如果项目用 Spring,可以把 Stub 配置成 Bean,但要注意 Axis1.4 的 Stub 不是线程安全的,每次调用最好新建实例,或者用ThreadLocal隔离。另外,Stub 里的setMaintainSession(true)可以保持 Session,但会增加内存开销。我一般会在 Spring 配置里用prototype作用域,确保每次注入都是新实例。还有一点,Axis1.4 依赖的commons-discovery和commons-logging版本较老,和 Spring Boot 的依赖可能冲突,需要排除掉。

<!-- Spring 配置 Stub Bean,prototype 作用域 --> <bean id="helloServiceStub" class="com.example.stub.HelloServiceSoapBindingStub" scope="prototype"> <!-- 设置服务端地址 --> <constructor-arg value="http://localhost:8080/axis/services/HelloService"/> <!-- 设置超时时间,单位毫秒 --> <property name="timeout" value="10000"/> </bean>

上面这段配置里,scope="prototype"保证每次注入都是新实例,避免线程安全问题。timeout设成 10000 毫秒,防止网络抖动导致请求堆积。如果服务端需要认证,还可以加username和password属性。集成后,建议写一个简单的单元测试,用MockWebService或者直接调本地服务验证,别等到上线才发现 Stub 没配好。

5.3 验证 Stub 是否正常的三个检查点

生成 Stub 后,别急着往业务代码里塞,先做三个检查:第一,用HelloServiceLocator拿到 Stub,调一个最简单的方法,看能否返回预期结果;第二,抓包看 SOAP 报文里的命名空间和参数名是否和服务端 WSDL 一致;第三,把 Stub 放到多线程环境里跑一下,看有没有AxisFault或连接泄漏。我一般会写一个main方法先跑通,再集成到 Spring。从那以后,每次拿到新的 WSDL,我都会先跑一遍WSDL2Java,确认生成的类能编译、能调用,再动业务代码。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询