Apache Axis 是早期 Java 平台上最主流的 Web Service 實作框架,雖然現已逐漸被 JAX-WS 等標準取代,但在維護舊系統或理解 SOAP 架構演進時仍具參考價值。本文詳細記錄 Axis 安裝、三種開發模式(DII、Stubs、Dynamic Proxy)與 WSDD 部署的完整實作流程。
webapps/axis 目錄複製至 TOMCAT_HOME/webapps/。https://localhost:8080/axis 確認安裝成功(應出現 Axis 服務列表頁)。| 模式 | 核心特性 | 優點 | 缺點 |
|---|---|---|---|
| DII (Dynamic Invocation Interface) | 執行期動態構建 Call 物件呼叫 | 無需預先產生 Stub,適合動態發現服務 | 程式碼冗長、型別安全性低、維護困難 |
| Stubs 方式 | 由 WSDL 產生強型別客戶端類別 | IDE 自動完成支援好、編譯期檢查、團隊協作友善 | 需額外建置步驟、WSDL 變更需重新產生 |
| Dynamic Proxy | 基於介面的動態代理,JSR-109 風格 | 程式碼簡潔、面向介面設計、解耦合度高 | 需理解 Proxy 機制、除錯相對困難 |
public class HelloClient {
public String getName(String name) {
return "hello " + name;
}
}
將檔案放入 AXIS_HOME 並命名為 HelloClient.jws,Axis 自動發布。
import org.apache.axis.client.Call;
import org.apache.axis.client.Service;
import javax.xml.namespace.QName;
import javax.xml.rpc.ServiceException;
import java.net.MalformedURLException;
import java.rmi.RemoteException;
public class TestHelloClient {
public static void main(String[] args) {
try {
String endpoint = "https://localhost:8080/axis/HelloClient.jws";
Service service = new Service();
Call call = (Call) service.createCall();
call.setOperationName(new QName("https://localhost:8080/axis/HelloClient.jws", "getName"));
call.setTargetEndpointAddress(new java.net.URL(endpoint));
String ret = (String) call.invoke(new Object[] {"張三"});
System.out.println("return value is " + ret);
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
public interface HelloClientInterface extends java.rmi.Remote {
public String getName(String name) throws java.rmi.RemoteException;
}
import javax.xml.rpc.Service;
import javax.xml.rpc.ServiceFactory;
import java.net.URL;
import javax.xml.namespace.QName;
public class TestHelloClient {
public static void main(String[] args) {
try {
String wsdlUrl = "https://localhost:8080/axis/HelloClient.jws?wsdl";
String namespaceUri = "https://localhost:8080/axis/HelloClient.jws";
String serviceName = "HelloClientService";
String portName = "HelloClient";
ServiceFactory factory = ServiceFactory.newInstance();
Service service = factory.createService(new URL(wsdlUrl), new QName(namespaceUri, serviceName));
HelloClientInterface proxy = (HelloClientInterface) service.getPort(new QName(namespaceUri, portName), HelloClientInterface.class);
System.out.println("return value is " + proxy.getName("John"));
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
package server;
public class SayHello {
public String getName(String name) {
return "hello " + name;
}
}
import org.apache.axis.AxisFault;
import org.apache.axis.Handler;
import org.apache.axis.MessageContext;
import org.apache.axis.handlers.BasicHandler;
import java.util.Date;
public class LogHandler extends BasicHandler {
public void invoke(MessageContext msgContext) throws AxisFault {
try {
Handler serviceHandler = msgContext.getService();
Integer numAccesses = (Integer) serviceHandler.getOption("accesses");
if (numAccesses == null) numAccesses = new Integer(0);
numAccesses = new Integer(numAccesses.intValue() + 1);
Date date = new Date();
String result = date + ": service " + msgContext.getTargetService() + " accessed " + numAccesses + " time(s).";
serviceHandler.setOption("accesses", numAccesses);
System.out.println(result);
} catch (Exception e) {
throw AxisFault.makeFault(e);
}
}
}
<deployment xmlns="https://xml.apache.org/axis/wsdd/"
xmlns:java="https://xml.apache.org/axis/wsdd/providers/java">
<handler name="print" type="java:LogHandler"/>
<service name="sayhello" provider="java:RPC">
<requestFlow><handler type="print"/></requestFlow>
<parameter name="className" value="server.SayHello"/>
<parameter name="allowedMethods" value="*"/>
</service>
</deployment>
# 複製編譯後的 class 到 AXIS_HOME/WEB-INF/classes
java org.apache.axis.client.AdminClient deploy.wsdd
方式一:從 .jws 產生
java org.apache.axis.wsdl.WSDL2Java -p client https://localhost:8080/axis/services/SayHello.jws?wsdl
方式二:從 Java 類別產生 WSDL 再產生 Stub
java org.apache.axis.wsdl.Java2WSDL -o SayHello.wsdl -l https://localhost:8080/axis/services/SayHello -n sayhello server.SayHello
java org.apache.axis.wsdl.WSDL2Java SayHello.wsdl -p client
public class SayHelloClient {
public static void main(String[] args) {
try {
SayHelloService service = new client.SayHelloServiceLocator();
client.SayHello_PortType client = service.getSayHello();
String retValue = client.getName("張三");
System.out.println(retValue);
} catch (Exception e) {
System.err.println("Execution failed. Exception: " + e);
}
}
}
axis.jar、jaxrpc.jar、saaj.jar、commons-logging.jar、commons-discovery.jar、wsdl4j.jar 皆在 Classpath 中。deploy.wsdd 中 service name 與 URL 路徑一致。-v 參數查看詳細錯誤訊息,或手動下載 WSDL 檔案離線產生。Axis 雖屬上一代技術,但其 DII、Stub、Dynamic Proxy 三種呼叫模式完整展示了 SOAP Web Service 的演進脈絡。理解這些基礎有助於維護舊系統、排查相容性問題,也能更深刻體會現代 JAX-WS / Spring WS 框架的設計哲學。