Java WebService动态调用
在Java中动态调用WebService有几种常见方法,以下是几种主要的实现方式:
使用JAX-WS动态调用
1 使用Dispatch API
import javax.xml.namespace.QName;
import javax.xml.soap.MessageFactory;
import javax.xml.soap.SOAPBody;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPMessage;
import javax.xml.ws.Dispatch;
import javax.xml.ws.Service;
import javax.xml.ws.soap.SOAPBinding;
import java.net.URL;
public class JAXWSDynamicClient {
public static void main(String[] args) throws Exception {
// 1. 创建Service实例
URL wsdlUrl = new URL("http://example.com/service?wsdl");
QName serviceName = new QName("http://example.com/", "MyService");
Service service = Service.create(wsdlUrl, serviceName);
// 2. 创建Dispatch实例
QName portName = new QName("http://example.com/", "MyPort");
Dispatch<SOAPMessage> dispatch = service.createDispatch(portName, SOAPMessage.class, Service.Mode.MESSAGE);
// 3. 创建SOAP请求
MessageFactory mf = MessageFactory.newInstance();
SOAPMessage request = mf.createMessage();
SOAPEnvelope envelope = request.getSOAPPart().getEnvelope();
SOAPBody body = envelope.getBody();
// 添加请求内容
body.addBodyElement(new QName("http://example.com/", "sayHello"))
.addTextNode("Dynamic Client");
// 4. 发送请求并获取响应
SOAPMessage response = dispatch.invoke(request);
response.writeTo(System.out);
}
}
2 使用Provider API
import javax.xml.namespace.QName;
import javax.xml.soap.MessageFactory;
import javax.xml.soap.SOAPMessage;
import javax.xml.ws.Dispatch;
import javax.xml.ws.Service;
import javax.xml.ws.Provider;
import javax.xml.ws.Service.Mode;
import javax.xml.ws.soap.SOAPBinding;
import java.net.URL;
public class JAXWSProviderClient {
public static void main(String[] args) throws Exception {
URL wsdlUrl = new URL("http://example.com/service?wsdl");
QName serviceName = new QName("http://example.com/", "MyService");
Service service = Service.create(wsdlUrl, serviceName);
QName portName = new QName("http://example.com/", "MyPort");
Dispatch<SOAPMessage> dispatch = service.createDispatch(portName, SOAPMessage.class, Mode.PAYLOAD);
// 创建请求
MessageFactory mf = MessageFactory.newInstance();
SOAPMessage request = mf.createMessage();
request.getSOAPBody().addBodyElement(new QName("http://example.com/", "sayHello"))
.addTextNode("Provider Client");
// 调用服务
SOAPMessage response = dispatch.invoke(request);
response.writeTo(System.out);
}
}
使用Apache CXF动态调用
1 使用JAX-WS前端
import org.apache.cxf.endpoint.Client;
import org.apache.cxf.frontend.ClientProxy;
import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
import org.apache.cxf.jaxws.JaxWsDynamicClientFactory;
public class CxfDynamicClient {
public static void main(String[] args) {
// 方法1: 使用JaxWsProxyFactoryBean
JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
factory.setServiceClass(MyService.class);
factory.setAddress("http://example.com/service");
MyService service = (MyService) factory.create();
String result = service.sayHello("CXF Client");
System.out.println(result);
// 方法2: 使用JaxWsDynamicClientFactory
JaxWsDynamicClientFactory dcf = JaxWsDynamicClientFactory.newInstance();
Client client = dcf.createClient("http://example.com/service?wsdl");
// 调用方法
Object[] response = client.invoke("sayHello", "Dynamic CXF");
System.out.println(response[0]);
}
}
2 使用CXF的Dispatch API
import org.apache.cxf.endpoint.Client;
import org.apache.cxf.frontend.ClientProxy;
import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
import org.apache.cxf.jaxws.JaxWsDynamicClientFactory;
import javax.xml.namespace.QName;
import javax.xml.soap.MessageFactory;
import javax.xml.soap.SOAPMessage;
import javax.xml.ws.Dispatch;
import javax.xml.ws.Service;
import java.net.URL;
public class CxfDispatchClient {
public static void main(String[] args) throws Exception {
URL wsdlUrl = new URL("http://example.com/service?wsdl");
QName serviceName = new QName("http://example.com/", "MyService");
Service service = Service.create(wsdlUrl, serviceName);
QName portName = new QName("http://example.com/", "MyPort");
Dispatch<SOAPMessage> dispatch = service.createDispatch(portName, SOAPMessage.class, Service.Mode.MESSAGE);
// 创建SOAP请求
MessageFactory mf = MessageFactory.newInstance();
SOAPMessage request = mf.createMessage();
request.getSOAPBody().addBodyElement(new QName("http://example.com/", "sayHello"))
.addTextNode("CXF Dispatch Client");
// 发送请求
SOAPMessage response = dispatch.invoke(request);
response.writeTo(System.out);
}
}
使用Axis 1.x动态调用
import org.apache.axis.client.Service;
import org.apache.axis.client.Call;
import javax.xml.namespace.QName;
import java.net.URL;
public class Axis1DynamicClient {
public static void main(String[] args) throws Exception {
String endpoint = "http://example.com/service";
String serviceName = "MyService";
String operationName = "sayHello";
Service service = new Service();
Call call = (Call) service.createCall();
call.setTargetEndpointAddress(new URL(endpoint));
call.setOperationName(new QName(serviceName, operationName));
Object[] params = new Object[]{"Axis Client"};
Object response = call.invoke(params);
System.out.println(response);
}
}
动态调用注意事项
- WSDL解析:动态调用通常需要WSDL文件来获取服务端点信息
- 性能考虑:动态调用比静态代理调用性能稍差,因为需要反射和动态解析
- 错误处理:需要妥善处理网络异常、SOAP异常等
- 安全性:考虑添加SOAP头信息处理认证等安全需求
- 复杂类型:对于复杂类型的参数,需要手动构造XML或使用JAXB进行转换
最佳实践建议
- 对于简单的WebService调用,优先考虑使用静态生成的客户端代码
- 当服务接口频繁变化或需要运行时动态选择服务时,使用动态调用
- 在生产环境中,建议使用成熟的框架如CXF或Spring-WS
- 考虑使用Spring的WebServiceTemplate来简化WebService调用
方法可以根据实际项目需求和技术栈选择合适的实现方式。
