如何配置Stub代理消费SOAP服务(javax ws)?开发环境替代第三方服务
太懂这种被第三方服务卡开发进度的痛苦了!我之前做JAX-WS SOAP客户端的时候,也折腾过类似的Stub配置,给你分享几个实用的方案,帮你在开发环境彻底摆脱对第三方应用的依赖:
方法1:用Mockito快速Mock Port接口(最简单高效)
如果你的核心需求只是验证业务逻辑,不需要模拟完整的SOAP消息结构,直接Mock生成的Port接口就完事了。毕竟JAX-WS生成的Port本身就是一个Java接口,Mockito可以直接接管它的方法返回:
// 假设你通过WSDL生成的Port接口是ThirdPartySoapPort public interface ThirdPartySoapPort extends javax.jws.WebService { ResponseData pushData(RequestData request); } // 开发环境中Mock这个接口 ThirdPartySoapPort mockPort = Mockito.mock(ThirdPartySoapPort.class); // 预设你想要的响应结果 ResponseData mockResponse = new ResponseData(); mockResponse.setStatus("SUCCESS"); mockResponse.setMessage("Mocked response from dev stub"); // 指定当调用pushData方法时,不管传入什么参数都返回预设响应 Mockito.when(mockPort.pushData(Mockito.any(RequestData.class))).thenReturn(mockResponse); // 接下来把这个mockPort注入到你的业务代码里,代替真实的Port即可
如果用Spring的话,还可以结合@Profile注解,让开发环境自动注入Mock实例,生产环境用真实客户端:
@Configuration public class SoapClientConfig { @Bean @Profile("dev") public ThirdPartySoapPort thirdPartySoapPortDev() { ThirdPartySoapPort mockPort = Mockito.mock(ThirdPartySoapPort.class); ResponseData mockResponse = new ResponseData(); mockResponse.setStatus("SUCCESS"); mockResponse.setMessage("Dev env mock response"); Mockito.when(mockPort.pushData(Mockito.any(RequestData.class))).thenReturn(mockResponse); return mockPort; } @Bean @Profile("prod") public ThirdPartySoapPort thirdPartySoapPortProd() { // 返回真实的SOAP客户端Port return new ThirdPartyService().getThirdPartySoapPort(); } }
方法2:通过JAX-WS Stub + 自定义Handler拦截并替换响应(适合模拟完整SOAP消息)
如果需要模拟更真实的SOAP交互(比如要验证SOAP消息的格式、处理Fault场景),可以利用JAX-WS的Stub接口和SOAPHandler来拦截请求并返回自定义的SOAP响应:
// 先获取真实的Port,然后强制转换为Stub(JAX-WS生成的Port默认实现了Stub接口) ThirdPartySoapPort realPort = new ThirdPartyService().getThirdPartySoapPort(); Stub stub = (Stub) realPort; // 创建自定义的SOAPHandler,用来替换响应 SOAPHandler<SOAPMessageContext> mockHandler = new SOAPHandler<>() { @Override public boolean handleMessage(SOAPMessageContext context) { // 判断当前是请求( outbound=true)还是响应(outbound=false)方向 Boolean isOutbound = (Boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); if (!isOutbound) { // 拦截响应,替换为我们预设的SOAP消息 try { // 构建Mock的SOAP响应 SOAPMessage mockSoapResponse = MessageFactory.newInstance().createMessage(); SOAPBody soapBody = mockSoapResponse.getSOAPBody(); // 根据WSDL定义的响应结构构建内容,这里举个例子: QName responseQName = new QName("http://your-thirdparty-namespace.com", "PushDataResponse"); SOAPElement responseElement = soapBody.addChildElement(responseQName); SOAPElement statusElement = responseElement.addChildElement("status"); statusElement.setValue("SUCCESS"); SOAPElement messageElement = responseElement.addChildElement("message"); messageElement.setValue("Mocked SOAP response from handler"); // 把Mock的消息设置回上下文,替代真实响应 context.setMessage(mockSoapResponse); } catch (SOAPException e) { e.printStackTrace(); } } return true; } @Override public boolean handleFault(SOAPMessageContext context) { // 如果需要模拟Fault场景,在这里处理即可 return true; } @Override public void close(MessageContext context) {} @Override public Set<QName> getHeaders() { return Collections.emptySet(); } }; // 将Handler添加到Stub的HandlerChain中 List<Handler> handlers = new ArrayList<>(); handlers.add(mockHandler); stub.setHandlerChain(handlers); // 现在调用stub的pushData方法,就会返回我们Mock的SOAP响应了
方法3:自定义Mock Service类(适合复杂场景)
如果上面两种方法满足不了你的需求(比如需要模拟不同场景的动态响应),可以自定义一个Mock Service类,继承自WSDL生成的Service类,重写getPort方法返回自己实现的Mock Port:
public class MockThirdPartyService extends ThirdPartyService { @Override public ThirdPartySoapPort getThirdPartySoapPort() { // 返回自定义的Mock Port实现 return new ThirdPartySoapPort() { @Override public ResponseData pushData(RequestData request) { // 这里可以根据请求参数动态返回不同响应 if (request.getUserId() == 123) { ResponseData response = new ResponseData(); response.setStatus("SUCCESS"); response.setMessage("User 123 processed"); return response; } else { ResponseData response = new ResponseData(); response.setStatus("FAILURE"); response.setMessage("Invalid user"); return response; } } }; } } // 开发环境中使用这个MockService代替真实的Service ThirdPartySoapPort mockPort = new MockThirdPartyService().getThirdPartySoapPort();
最后小提示
- 开发环境记得把SOAP客户端的日志打开,方便验证Mock的响应是否符合预期。
- 如果需要模拟不同的业务场景,可以结合配置文件(比如application-dev.properties)来动态调整Mock响应的内容。
内容的提问来源于stack exchange,提问作者eswarpalani
相关产品推荐
相关产品推荐

