Spring环境调用SOAP服务报错:无法定位有效EngineConfigurationFactory
问题分析与解决方案
你遇到的空指针异常,根源是Apache Axis这个旧框架和新的Spring Boot 2环境兼容性不匹配。Axis在Spring Boot的类加载机制下,找不到它需要的EngineConfigurationFactory实现类,导致初始化Service时抛出NPE。既然不想生成Stub,而且所有服务方法都返回字节数组,推荐你用以下两种更适配当前技术栈的简易方案:
方案一:用Spring WebServiceTemplate(推荐,贴合Spring生态)
Spring自带的WebServiceTemplate可以直接构造SOAP请求并调用服务,无需生成Stub。步骤如下:
1. 添加Gradle依赖
implementation 'org.springframework.boot:spring-boot-starter-web-services'
2. 配置WebServiceTemplate Bean
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.ws.client.core.WebServiceTemplate; import org.springframework.ws.transport.http.HttpUrlConnectionMessageSender; @Configuration public class SoapClientConfig { @Bean public WebServiceTemplate webServiceTemplate() { WebServiceTemplate template = new WebServiceTemplate(); // 设置HTTP消息发送器 template.setMessageSender(new HttpUrlConnectionMessageSender()); // 配置SOAP服务的端点地址 template.setDefaultUri("http://docsystem.intra.com:18080/documents/services"); return template; } }
3. 编写调用逻辑
import org.springframework.stereotype.Service; import org.springframework.ws.client.core.WebServiceTemplate; import org.springframework.ws.soap.client.core.SoapActionCallback; import org.springframework.ws.soap.saaj.SaajSoapMessage; import javax.xml.soap.SOAPBody; import javax.xml.soap.SOAPElement; import javax.xml.soap.SOAPException; import java.io.ByteArrayOutputStream; import java.io.IOException; @Service public class DocumentSoapClient { private final WebServiceTemplate webServiceTemplate; // 构造注入WebServiceTemplate public DocumentSoapClient(WebServiceTemplate webServiceTemplate) { this.webServiceTemplate = webServiceTemplate; } public byte[] callService(String methodName, Object... params) throws SOAPException, IOException { // 创建SOAP请求消息 SaajSoapMessage request = (SaajSoapMessage) webServiceTemplate.createWebServiceMessage(); SOAPBody soapBody = request.getSaajMessage().getSOAPBody(); // 构造请求元素(注意替换成实际的命名空间和方法参数) SOAPElement requestElement = soapBody.addChildElement(methodName, "", "http://server.priv.doc/"); // 添加方法参数(根据实际需求调整) for (int i = 0; i < params.length; i++) { SOAPElement param = requestElement.addChildElement("param" + (i + 1)); param.setValue(params[i].toString()); } // 发送请求并获取响应 SaajSoapMessage response = (SaajSoapMessage) webServiceTemplate.sendAndReceive( request, new SoapActionCallback("http://server.priv.doc/" + methodName) ); // 将响应转为字节数组返回 ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); response.writeTo(outputStream); return outputStream.toByteArray(); } }
方案二:用原生HTTP客户端(轻量无额外依赖)
如果不想引入Spring WS的依赖,也可以直接用Java原生的HttpURLConnection发送SOAP请求,手动构造SOAP信封:
import java.io.ByteArrayOutputStream; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URL; public class SimpleSoapClient { public byte[] callSoapService(String endpoint, String methodName, String namespace) throws Exception { // 构造SOAP信封(根据实际WSDL调整参数部分) String soapEnvelope = String.format( "<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:ser=\"%s\">" + " <soapenv:Header/>" + " <soapenv:Body>" + " <ser:%s>" + " <!-- 这里添加你的方法参数,比如 <ser:documentId>123</ser:documentId> -->" + " </ser:%s>" + " </soapenv:Body>" + "</soapenv:Envelope>", namespace, methodName, methodName ); // 建立HTTP连接 URL url = new URL(endpoint); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setRequestMethod("POST"); connection.setRequestProperty("Content-Type", "text/xml;charset=UTF-8"); connection.setRequestProperty("SOAPAction", namespace + methodName); connection.setDoOutput(true); // 发送SOAP请求 connection.getOutputStream().write(soapEnvelope.getBytes("UTF-8")); // 读取响应字节 InputStream inputStream = connection.getInputStream(); ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; int len; while ((len = inputStream.read(buffer)) != -1) { outputStream.write(buffer, 0, len); } // 关闭资源 inputStream.close(); connection.disconnect(); return outputStream.toByteArray(); } // 使用示例 public static void main(String[] args) throws Exception { SimpleSoapClient client = new SimpleSoapClient(); byte[] result = client.callSoapService( "http://docsystem.intra.com:18080/documents/services", "getDocument", // 替换为实际方法名 "http://server.priv.doc/" ); // 处理返回的字节数组 } }
为什么旧的Axis代码不能用了?
旧项目中的Axis依赖可能完整包含了配置工厂的实现,但在Spring Boot 2环境下,要么是依赖冲突导致Axis的配置类被覆盖,要么是类加载顺序问题让Axis找不到所需的实现类,最终触发NPE。放弃旧的Axis框架,改用更适配现代Spring环境的方式,是更稳定的选择。
内容的提问来源于stack exchange,提问作者tomas
相关产品推荐
相关产品推荐

