2016-04-22 136 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只是吃角色的選擇。) –