1. 概述
Java API for XML Web Services (JAX-WS) 是一套标准化的 API,用于创建和消费 SOAP(简单对象访问协议)Web 服务。
本文将带你:
- ✅ 创建一个 SOAP Web 服务
- ✅ 使用 JAX-WS 连接该服务
2. SOAP 协议
SOAP 是一种基于 XML 的网络消息传输规范,具有以下特点:
- ✅ 跨平台兼容:与操作系统无关
- ✅ 协议无关:支持 HTTP、SMTP 等多种通信协议
- ⚠️ XML 冗余:消息体积较大,必须配合工具/框架使用
JAX-WS 作为 Java 标准的一部分,简化了 SOAP 的使用,是 Java 开发者的首选方案。
3. 开发模式对比
开发 SOAP Web 服务有两种主流模式:
3.1 自顶向下(契约优先)
- 流程:先创建 WSDL 文件 → 生成 Java 类
- 优势:契约稳定,代码变动不影响接口定义
- 劣势:编写复杂 WSDL 文件门槛较高
3.2 自底向上(代码优先)
- 流程:先写 Java 类 → 自动生成 WSDL
- 优势:开发效率高,适合快速迭代
- 劣势:代码修改可能导致 WSDL 变更
⚠️ 踩坑提醒:生产环境推荐自顶向下模式,确保接口稳定性;原型开发可用自底向上模式快速验证。
4. WSDL 核心结构
WSDL 是 Web 服务的契约定义文件,采用 XML 格式描述服务接口。其核心元素包括:
4.1 Definitions(根元素)
定义服务名称、命名空间等全局信息:
<definitions xmlns="http://schemas.xmlsoap.org/wsdl/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:tns="http://jaxws.baeldung.com/"
xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata"
xmlns:wsp="http://www.w3.org/ns/ws-policy"
xmlns:wsp1_2="http://schemas.xmlsoap.org/ws/2004/09/policy"
xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://jaxws.baeldung.com/"
name="EmployeeService">
...
</definitions>
4.2 Types(数据类型)
使用 XSD(XML Schema Definition)定义数据类型:
<types>
<xsd:schema>
<xsd:import namespace="http://jaxws.baeldung.com/"
schemaLocation = "http://localhost:8080/employeeservice?xsd=1" />
</xsd:schema>
</types>
4.3 Messages(消息抽象)
定义输入、输出和异常消息:
<message name="getEmployee">
<part name="parameters" element="tns:getEmployee" />
</message>
<message name="getEmployeeResponse">
<part name="parameters" element="tns:getEmployeeResponse" />
</message>
<message name="EmployeeNotFound">
<part name="fault" element="tns:EmployeeNotFound" />
</message>
4.4 PortType(操作集合)
描述服务操作及其关联消息:
<portType name="EmployeeService">
<operation name="getEmployee">
<input wsam:Action="http://jaxws.baeldung.com/EmployeeService/getEmployeeRequest"
message="tns:getEmployee" />
<output wsam:Action="http://jaxws.baeldung.com/EmployeeService/getEmployeeResponse"
message="tns:getEmployeeResponse" />
<fault message="tns:EmployeeNotFound" name="EmployeeNotFound"
wsam:Action="http://jaxws.baeldung.com/EmployeeService/getEmployee/Fault/EmployeeNotFound" />
</operation>
</portType>
4.5 Binding(协议绑定)
指定通信协议和数据格式:
<binding name="EmployeeServiceImplPortBinding" type="tns:EmployeeService">
<soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document" />
<operation name="getEmployee">
<soap:operation soapAction="" />
<input><soap:body use="literal" /></input>
<output><soap:body use="literal" /></output>
<fault name="EmployeeNotFound">
<soap:fault name="EmployeeNotFound" use="literal" />
</fault>
</operation>
</binding>
4.6 Service(服务端点)
定义服务访问地址:
<service name="EmployeeService">
<port name="EmployeeServiceImplPort" binding="tns:EmployeeServiceImplPortBinding">
<soap:address location="http://localhost:8080/employeeservice" />
</port>
</service>
5. 自顶向下开发实践
5.1 创建 WSDL 文件
以下为简化版 WSDL 示例(employeeservicetopdown.wsdl
):
<?xml version="1.0" encoding="UTF-8"?>
<definitions
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:tns="http://topdown.server.jaxws.baeldung.com/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns="http://schemas.xmlsoap.org/wsdl/"
targetNamespace="http://topdown.server.jaxws.baeldung.com/"
qname="EmployeeServiceTopDown">
<types>
<xsd:schema targetNamespace="http://topdown.server.jaxws.baeldung.com/">
<xsd:element name="countEmployeesResponse" type="xsd:int"/>
</xsd:schema>
</types>
<message name="countEmployees"/>
<message name="countEmployeesResponse">
<part name="parameters" element="tns:countEmployeesResponse"/>
</message>
<portType name="EmployeeServiceTopDown">
<operation name="countEmployees">
<input message="tns:countEmployees"/>
<output message="tns:countEmployeesResponse"/>
</operation>
</portType>
<binding name="EmployeeServiceTopDownSOAP" type="tns:EmployeeServiceTopDown">
<soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"/>
<operation name="countEmployees">
<soap:operation soapAction="http://topdown.server.jaxws.baeldung.com/EmployeeServiceTopDown/countEmployees"/>
<input><soap:body use="literal"/></input>
<output><soap:body use="literal"/></output>
</operation>
</binding>
<service name="EmployeeServiceTopDown">
<port name="EmployeeServiceTopDownSOAP" binding="tns:EmployeeServiceTopDownSOAP">
<soap:address location="http://localhost:8080/employeeservicetopdown"/>
</port>
</service>
</definitions>
5.2 生成 Java 代码
使用 JDK 内置的 wsimport
工具生成服务端代码:
wsimport -s . -p com.baeldung.jaxws.server.topdown employeeservicetopdown.wsdl
关键参数说明:
-p
:指定目标包名-s
:指定源码输出目录
💡 替代方案:JDK 9+ 可使用 jaxws-maven-plugin 或 maven-jaxb2-plugin
生成文件清单:
EmployeeServiceTopDown.java
:服务接口(SEI)ObjectFactory.java
:对象工厂类EmployeeServiceTopDown_Service.java
:服务提供者类
5.3 实现服务接口
生成的接口示例:
@WebService(
name = "EmployeeServiceTopDown",
targetNamespace = "http://topdown.server.jaxws.baeldung.com/")
@SOAPBinding(parameterStyle = SOAPBinding.ParameterStyle.BARE)
@XmlSeeAlso({ObjectFactory.class})
public interface EmployeeServiceTopDown {
@WebMethod(
action = "http://topdown.server.jaxws.baeldung.com/EmployeeServiceTopDown/countEmployees")
@WebResult(
name = "countEmployeesResponse",
targetNamespace = "http://topdown.server.jaxws.baeldung.com/",
partName = "parameters")
public int countEmployees();
}
实现类示例:
@WebService(
name = "EmployeeServiceTopDown",
endpointInterface = "com.baeldung.jaxws.server.topdown.EmployeeServiceTopDown",
targetNamespace = "http://topdown.server.jaxws.baeldung.com/")
public class EmployeeServiceTopDownImpl implements EmployeeServiceTopDown {
@Inject
private EmployeeRepository employeeRepositoryImpl;
@WebMethod
public int countEmployees() {
return employeeRepositoryImpl.count();
}
}
6. 自底向上开发实践
6.1 创建模型类
public class Employee {
private int id;
private String firstName;
// 标准 getter/setter
}
6.2 定义服务接口
@WebService
public interface EmployeeService {
@WebMethod Employee getEmployee(int id);
@WebMethod Employee updateEmployee(int id, String name);
@WebMethod boolean deleteEmployee(int id);
@WebMethod Employee addEmployee(int id, String name);
}
注解说明:
@WebService
:标记为 Web 服务接口@WebMethod
:声明服务操作@WebResult
:自定义返回值 XML 元素名
6.3 实现服务类
@WebService(endpointInterface = "com.baeldung.jaxws.EmployeeService")
public class EmployeeServiceImpl implements EmployeeService {
@Inject
private EmployeeRepository employeeRepositoryImpl;
@WebMethod
public Employee getEmployee(int id) {
return employeeRepositoryImpl.getEmployee(id);
}
// 其他方法实现...
}
7. 发布服务端点
通过 javax.xml.ws.Endpoint
发布服务:
public class EmployeeServicePublisher {
public static void main(String[] args) {
// 发布自顶向下服务
Endpoint.publish(
"http://localhost:8080/employeeservicetopdown",
new EmployeeServiceTopDownImpl());
// 发布自底向上服务
Endpoint.publish("http://localhost:8080/employeeservice",
new EmployeeServiceImpl());
}
}
💡 生产建议:将服务打包为 WAR 部署到 WildFly/GlassFish 等应用服务器,以支持 CDI 等企业特性。
8. 远程客户端调用
8.1 生成客户端代码
使用 wsimport
生成客户端存根:
wsimport -keep -p com.baeldung.jaxws.client http://localhost:8080/employeeservice?wsdl
8.2 调用远程服务
public class EmployeeServiceClient {
public static void main(String[] args) throws Exception {
URL url = new URL("http://localhost:8080/employeeservice?wsdl");
// 创建服务代理
EmployeeService_Service service = new EmployeeService_Service(url);
EmployeeService proxy = service.getEmployeeServiceImplPort();
// 调用远程方法
List<Employee> allEmployees = proxy.getAllEmployees();
}
}
9. 总结
本文系统介绍了 JAX-WS 开发 SOAP Web 服务的核心知识:
- ✅ 两种开发模式:自顶向下(契约优先)vs 自底向上(代码优先)
- ✅ WSDL 结构解析:六大核心元素详解
- ✅ 服务发布与调用:从开发到部署全流程
- ✅ 客户端集成:远程服务调用实践
⚠️ 简单粗暴建议:新项目优先选择 RESTful 风格(如 JAX-RS),SOAP 仅用于需要强契约的企业级集成场景。
完整源码请参考 GitHub 仓库。