2016-04-22 137 views
-1

我试图获得SOAPMessage对象的原始xml,我正在使用ByteArrayOutputStream类,但是它的可读性一旦存在压缩附件就添加到消息对象中。只接收部分消息写入ByteArrayOutputStream对象

这里是我的代码:

ByteArrayOutputStream out = new ByteArrayOutputStream(); 
message.writeTo(out); 
strMsg = new String(out.toByteArray()); 

其中,消息是SOAPMessage对象。 问题是,当我将它打印到标准输出或日志或其他输出时,strMsg可能很大并且包含压缩附件的字节数据。在将消息写入ByteArrayOutputStream对象的时刻,有没有办法截断它?我知道,我可以轻松截断strMsg,但我没有看到收集ByteArrayOutputStream中所有数据的理由。

+0

如果数据是压缩的,它不会*有任何丢失的可读性,并且您没有任何业务试图首先将它转换为字符串。不清楚你真正想问什么。 – EJP

+0

@EJP - 我很清楚。他试图在日志中捕获SOAP消息,而不会在有附件时填充大量不可读的东西来填充日志文件。 –

+0

@StephenC因此他需要通过SoapMessage API获取可读的消息片段并记录下来。不要把整个事物转换成一个'ByteArrayOutputStream',然后是一个'String',它并没有开始实现这个目标。 – EJP

回答

1

我知道,我可以很容易地截断strMsg,但我没有看到收集ByteArrayOutputStream中所有数据的理由。

问题是,您只有writeTo方法可以使用,并且该方法用于输出整个消息。

您可以创建ByteArrayOutputStream的自定义变体,它只接受指定的字节数。如果writeTo超出限制,您的类需要抛出IO异常。

实际问题是创建和抛出异常很昂贵。这是口头禅的真正基础:“仅在特殊情况下使用例外” - https://softwareengineering.stackexchange.com/questions/184654/ive-been-told-that-exceptions-should-only-be-used-in-exceptional-cases-how-do。如果您记录了很多SOAP消息,那可能是一个问题。

异常创建/抛出的主要性能瓶颈实际上是异常对象的创建:特别是Throwable构造函数调用fillInStacktrace来捕获堆栈帧的部分。有一对夫妇的方式来改善这一点:

  • 代替new -ing异常每次对象,你可以创建一个实例,它缓存在一个“全球性”,并重复使用多次。

  • 如果异常是自定义异常,则可以覆盖其fillInStacktrace方法以免执行任何操作。

在这两种情况下,如果您尝试打印堆栈跟踪,最终会出现异常,从而导致错误结果。但是,如果您使用异常来实现“非例外”代码路径(因为您没有真正的选择!),那么这可能不相关。


我的解决方案上面有一个变体,其中自定义字节接收器类默默抛出字节而不是抛出异常。这避免了异常的成本(但见上文),但它并不能避免writeOut在将大型SOAP消息序列化到已停止监听的字节接收器时所做的不必要的工作。


另外要注意的是截断后的字节一定数量的是承担责任,如果您使用的是多字节字符编码,如UTF-8打破。考虑如果以100字节截断并且第100个字节位于字符中间会发生什么情况。请注意,如果byte[]包含的序列在默认字符集中不是有效字符,则未指定new String(byte[])的行为。

+0

为什么这个答案的四个方面是关于异常的?当你输出大量数据时,如果你得到一个异常,那么一个异常的小开销是不相关的。实际上,为什么这个类会抛出一个异常,没有什么真正的原因。但为什么他不使用'writeTo(System.out)',或者他为什么要尝试记录压缩数据呢,这是真正的问题。 – EJP

+0

@EJP - 这取决于抛出异常的频率以及消息大小的扩展。无论如何,我按照自己写的方式写答案,因为那是我认为读者需要知道的。如果您认为需要说不同的话,请随时编写您自己的答案。 –

+0

@EJP - *“没有什么真正的原因,为什么这个班会实际上抛出一个异常。”* - 其实有。 'writeTo'方法做了很多工作(例如XML DOM解析)来生成序列化的字节。如果抛出异常,那么你可以节省大量不必要的工作。 (是的,我确实考虑过自定义BAOS只是吃角色的选择。) –