首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Apache cxf和大型SOAP请求

Apache cxf和大型SOAP请求
EN

Stack Overflow用户
提问于 2020-09-24 08:29:08
回答 1查看 548关注 0票数 0

我可能会有一个大型请求(SOAP)来到应用服务器通配符20,我想知道如何处理该请求,而不必将所有请求解析在内存中。

我的问题是,在CXF调用DocLiteralnInterceptor拦截器之后,请求本身成为内存中的一个完整对象。如何避免这种情况?对于我来说,在不破坏与SOAP请求相关的cxf预期功能的情况下,删除这个拦截器安全吗?

拦截器中的默认CXF

  1. AttachmentInInterceptor
  2. StaxInInterceptor
  3. ReadHeadersInterceptor
  4. SoapActionInInterceptor
  5. MustUnderstandInterceptor
  6. SOAPHandlerInterceptor
  7. LogicalHandlerInInterceptor
  8. CheckFaultInterceptor
  9. URIMappingInterceptor
  10. DocLiteralnInterceptor
  11. SoapHeaderInterceptor
  12. WrapperClassInInterceptor
  13. SwAInInterceptor
  14. HolderInInterceptor
  15. ServiceInvokerInInterceptor

我的第一个想法是删除从10到15包含的所有拦截器,并编写一个拦截器来解析给定的请求(stax),但是我不知道如何处理解析的块,以及如何同时将处理过的块写入输出流,是否需要使用线程?我是否需要删除输出拦截器(这会破坏cxf)?

但是,拦截器只用于预处理或后处理--请求和业务逻辑应该在web服务方法中调用,但在这种情况下,我需要绕过web服务方法,从inInterceptor直接转到outInterceptor,对吗?

我的第二个想法是在DocLiteralnInterceptor解析一段请求(比如1000个subObject元素)之前添加拦截器,并将其封装到根(对象)元素中,并多次从启动DocLiteralnInterceptor,的拦截器链调用,这个解决方案是否可行?如果是的话,我怎么能这样做呢?在这种情况下,我不需要绕过webservice方法。但不确定这个解决方案在一般情况下是否可行

我的请求对象示例如下

代码语言:javascript
复制
<?xml version="1.0" encoding="UTF-8"?>
<object>
   <subObject>
      <id>12</id>
      <item>
         <id>15</id>
         <name>block</name>
         ...<- other fields
      </item>
   </subObject>
   ...<- subObject element repeated 500k (500, 000) times
</object>
EN

回答 1

Stack Overflow用户

发布于 2020-09-27 16:09:37

不确定是否可以在没有mtom的大请求中有效地使用cxf。

您可以尝试使用提供程序接口处理请求。

代码语言:javascript
复制
public class MyService implements Provider<StAXSource> {
}

但是,如果您的响应也比我怀疑的提供者接口对您的帮助要大,因为您似乎需要返回StAXSource,如果您的请求很大,则需要消耗大量内存。

https://docs.oracle.com/middleware/1213/wls/WSGET/jax-ws-provider.htm#WSGET656

从上面的链接复制粘贴

代码语言:javascript
复制
package examples.webservices.jaxws;
 
import org.w3c.dom.Node;
 
import javax.xml.transform.Source;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.stream.StreamSource;
import javax.xml.ws.Provider;
import javax.xml.ws.ServiceMode;
import javax.xml.ws.WebServiceProvider;
import javax.xml.ws.Service;
import java.io.ByteArrayInputStream;
 
 
/**
 * A simple Provider-based web service implementation.
 *
 * @author Copyright (c) 2010, Oracle and/or its affiliates. 
 * All Rights Reserved.
 */
// The @ServiceMode annotation specifies whether the Provider instance 
// receives entire messages or message payloads.
@ServiceMode(value = Service.Mode.PAYLOAD)

// Standard JWS annotation that configures the Provider-based web service.
@WebServiceProvider(portName = "SimpleClientPort",
    serviceName = "SimpleClientService",
    targetNamespace = "http://jaxws.webservices.examples/",
    wsdlLocation = "SimpleClientService.wsdl")
public class SimpleClientProviderImpl implements Provider<Source> {
 
  //Invokes an operation according to the contents of the request message.
  public Source invoke(Source source) {
    try {
      DOMResult dom = new DOMResult();
      Transformer trans = TransformerFactory.newInstance().newTransformer();
      trans.transform(source, dom);
      Node node = dom.getNode();
      // Get the operation name node.
      Node root = node.getFirstChild();
      // Get the parameter node.
      Node first = root.getFirstChild();
      String input = first.getFirstChild().getNodeValue();
      // Get the operation name.
      String op = root.getLocalName();
      if ("invokeNoTransaction".equals(op)) {
        return sendSource(input);
      } else {
        return sendSource2(input);
      }
    }
    catch (Exception e) {
      throw new RuntimeException("Error in provider endpoint", e);
    }
  }
 
  private Source sendSource(String input) {
    String body =
        "<ns:invokeNoTransactionResponse
             xmlns:ns=\"http://jaxws.webservices.examples/\"><return>"
            + "constructed:" + input
            + "</return></ns:invokeNoTransactionResponse>";
    Source source = new StreamSource(new ByteArrayInputStream(body.getBytes()));
    return source;
  }
 
  private Source sendSource2(String input) {
    String body =
        "<ns:invokeTransactionResponse 
            xmlns:ns=\"http://jaxws.webservices.examples/\"><return>"
            + "constructed:" + input
            + "</return></ns:invokeTransactionResponse>";
    Source source = new StreamSource(new ByteArrayInputStream(body.getBytes()));
    return source;
  }
 
} 

如您所见,xml响应字符串保存在内存中。

您也可以尝试使用调度接口,即

(从同一链接复制)

代码语言:javascript
复制
package jaxws.dispatch.client;
 
import java.io.ByteArrayOutputStream;
import java.io.OutputStream;
import java.io.StringReader;
import java.net.URL;
 
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPMessage;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;

import javax.xml.ws.Dispatch;
import javax.xml.ws.Service;
import javax.xml.ws.WebServiceException;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.namespace.QName;
import javax.xml.ws.soap.SOAPBinding;
 
public class WebTest extends TestCase {
   private static String in_str = "wiseking";
   private static String request = 
      "<ns1:sayHello xmlns:ns1=\"http://example.org\"><arg0>"+in_str+"</arg0></ns1:sayHello>";
 
   private static final QName portQName = new QName("http://example.org", "SimplePort");
   private Service service = null;

   protected void setUp() throws Exception {
 
      String url_str = System.getProperty("wsdl");
      URL url = new URL(url_str);
      QName serviceName = new QName("http://example.org", "SimpleImplService");
      service = Service.create(serviceName);
      service.addPort(portQName, SOAPBinding.SOAP11HTTP_BINDING, url_str);
      System.out.println("Setup complete.");
 
   }
 
   public void testSayHelloSource() throws Exception {
      setUp();
      Dispatch<Source> sourceDispatch = 
         service.createDispatch(portQName, Source.class, Service.Mode.PAYLOAD);
      System.out.println("\nInvoking xml request: " + request);
      Source result = sourceDispatch.invoke(new StreamSource(new StringReader(request)));
      String xmlResult = sourceToXMLString(result);
      System.out.println("Received xml response: " + xmlResult);
      assertTrue(xmlResult.indexOf("HELLO:"+in_str)>=0);
   }
 
   private String sourceToXMLString(Source result) {
      String xmlResult = null;
      try {
         TransformerFactory factory = TransformerFactory.newInstance();
         Transformer transformer = factory.newTransformer();
         transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
         transformer.setOutputProperty(OutputKeys.METHOD, "xml");
         OutputStream out = new ByteArrayOutputStream();
         StreamResult streamResult = new StreamResult();
         streamResult.setOutputStream(out);
         transformer.transform(result, streamResult);
         xmlResult = streamResult.getOutputStream().toString();
      } catch (TransformerException e) {
         e.printStackTrace();
      }
      return xmlResult;
   }
 
}

另一方面,您可以编写自己的servlet实现,它接受大型请求并逐段处理,并作为输出返回一些内容。

但总的来说,我怀疑没有mtom或类似的东西,用cxf处理大型请求是否可行。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/64042452

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档