在CXF拦截器中保存出站邮件

时间:2013-12-19 15:28:51

标签: java io cxf

我对CXF有一个非常难的问题,我试图解决(失败)一个多月。我读过很多类似的问题,但没有什么可以帮助我。

首先,让我介绍一下我用来保存出站邮件的部分代码:

  public void handleMessage(SoapMessage message) throws Fault {
        OutputStream os = message.getContent(OutputStream.class);
        CacheAndWriteOutputStream cwos = new CacheAndWriteOutputStream(os);
        message.setContent(OutputStream.class, cwos);
        cwos.registerCallback(new LoggingOutCallBack());
    }

    class LoggingOutCallBack implements CachedOutputStreamCallback
    {
        public void onClose (CachedOutputStream cos)
        {
            try
            {
                String result = IOUtils.toString(cos.getInputStream());
            }
            catch (Exception e)
            {
                LogFactory.getLog(SwcFinalResponseInterceptor.class).error(ExceptionUtils.getStackTrace(e));
            }
        }

        public void onFlush (CachedOutputStream arg)
        {
        }
    }

我使用 PRE_STREAM 阶段。许多地方都提到了这种方法(例如,here),但它会导致一些罕见的错误。我每天大约有20000个请求,因此,对于200个大请求,这种方法失败了 - 对于其中一个请求,我得到流关闭错误。

2013-12-19 15:37:47,902 [WARN ] org.apache.cxf.common.logging.LogUtils.doLog(LogUtils.java:400)
5880162-Interceptor for {http://service.ws.swc.comtech/}FrequentFlyerServiceWsService has thrown exception, unwinding now
5880163-org.apache.cxf.interceptor.Fault: Stream closed
5880164-        at org.apache.cxf.interceptor.LoggingInInterceptor.logging(LoggingInInterceptor.java:144)
5880165-        at org.apache.cxf.interceptor.LoggingInInterceptor.handleMessage(LoggingInInterceptor.java:73)

我绝对相信这是因为我的代码中的这一行:

cos.getInputStream()

我已经测试了很多次没有这一行,并且一切正常,但是当我添加这一行时,错误会立即出现。 我想这是因为CXF存储的流数据不是存储在内存中的大流,而是存储在一些临时文件中。它被描述为here

一个有趣的观点是,当我尝试自己加载测试服务器时,发送数千个带有curl的重请求,没有错误,但是当有很多客户端时,问题几乎立即开始出现。

我还发现了another solution,乍一看,似乎工作正常,我不再有了 流关闭错误,但服务器开始跳过某些响应。

请帮助我,我真的不知道我还能读什么或做什么,我不擅长溪流和 CXF,但我需要一个有效的解决方案,如果你能解释我做错了什么就会很棒。

如果你不能直接回答这个问题,请至少回答其中一些问题:

  1. 为什么需要此行 message.setContent(OutputStream.class,cwos); ? 我不想修改流内容,只是得到里面的内容,那么我为什么要阅读然后再发送内容呢?

  2. 可能有比这个 message.getContent(OutputStream.class); 更合适的格式(要获取的类)?

  3. 可能我应该使用另一个拦截阶段?

  4. 有一种方法 onClose ,在流关闭或AFTER之前触发?这什么时候发生的?我不希望在将内容作为请求发送给客户端之前关闭strem。

  5. 提前致谢!

1 个答案:

答案 0 :(得分:3)

我理解你的问题的方式:

  1. 如果您只想记录SOAP请求响应信封,您甚至不应该使用StreamInterceptor。最好使用LoggingInterceptor。回答你的第一个问题 message.setContent(OutputStream.class,cwos);拦截传出的soap消息并更改其中的内容。

  2. 如果您想继续使用StreamInterceptor,最终会使用相同的方法来获取OutputStream的内容。另一种方法是使用LoggingInterceptor。 有关这方面的更多信息 How to log Apache CXF Soap Request and Soap Response using Log4j

  3. 您可以继续使用pre-stream。但如果目的只是阅读邮件内容,则可以使用pre_invoke。使用一个而不是另一个没有优势。 这里有一个链接,可以让您了解如何扩展一个简单的类来实现LoggingInterceptor。 http://cxf.apache.org/docs/interceptors.html

    How to get incoming & outgoing soap xml in a simple way using Apache CXF?