場景
場景是這樣的:客戶端.NET 3.5應用程序,WCF實現WebService調用, 服務端Java,通過CXF提供WebService。 有一個方法提供了有一個字符串類型的參數,實際生產環境里會傳100k以上的字符串。在并發量比較大的情況下,帶寬占用很嚴重。所以尋找一種可以把傳輸的 SOAP消息在客戶端壓縮,服務端解壓縮的方法。
這里提供的方式在是客戶端通過WCF的MessageEncoder機制對所有的SOAP請求消息壓縮,SOAP響應消息解壓縮,反過來在服務端通過一個Filter對所有的SOAP請求消息,對SOAP響應消息壓縮。
請求的流程如下:
Client -> SOAP Request -> GzipMessageEncoder -> gzip binary -> GzipWebSericeFilter -> SOAP Request -> CXF
響應的流程如下:
CXF -> SOAP Response -> GzipWebServiceFilter -> gzip binary -> GzipMessageEncoder -> SOAP Response -> Client
其中.NET的WCF的GzipMessageEncoder是參照WCF的Samples, 下載解壓后路徑WF_WCF_Samples\WCF\Extensibility\MessageEncoder\Compression
客戶端
下面先來看一下客戶端部分的代碼:
GZipMessageEncoderFactory.cs 這文件主要是提供GZipMessageEncoder,在里面通過重寫ReadMessage和WriteMessage方法來實現壓縮和解壓縮。 實際壓縮和解壓處理是使用GZipStream實現的。
下面是GZipMessageEncodingBindingElement.cs 這里的GZipMessageEncodingBindingElement類是為了在app.config里添加配置項。
然后我們就可以把這個GZipMessageEncodingElement配置到app.config里了
客戶端最后的部分就是調用webservice, 這里的壓縮和解壓對于調用者和陪調用者是透明的。也就是同沒有壓縮和解壓之前的使用方法一樣。
服務端
服務端是一個Filter,和HttpServletRequest和HttpServletResponse的包裝類。
入口:GzipWebServiceFilter.java
這里就是判斷contentType,如果是gzip的就用GzipHttpServletRequestWrapper和GzipHttpServletResponseWrapper包裝原始的Request和Response以實現壓縮和解壓縮。
GzipHttpServletRequestWrapper
GzipHttpServletResponseWrapper
然后在web.xml中把這個Filter作用于原來的WebService的Servlet
web.xml
webservice的配置和cxf原來的一樣

本文的源代碼在附件中。
本文的方案沒有在最終的被用于生產環境,一個原因是比較復雜,另外一個是服務器在對大XML進行unmarshal的效率并不高。單本文的方案的好處就是不用對原有的webservice接口和實現進行修改。 最后在實際場景用我們使用MTOM來解決問題的, 后面我還會寫一篇文章來介紹這個方法。
source.zip
場景是這樣的:客戶端.NET 3.5應用程序,WCF實現WebService調用, 服務端Java,通過CXF提供WebService。 有一個方法提供了有一個字符串類型的參數,實際生產環境里會傳100k以上的字符串。在并發量比較大的情況下,帶寬占用很嚴重。所以尋找一種可以把傳輸的 SOAP消息在客戶端壓縮,服務端解壓縮的方法。
這里提供的方式在是客戶端通過WCF的MessageEncoder機制對所有的SOAP請求消息壓縮,SOAP響應消息解壓縮,反過來在服務端通過一個Filter對所有的SOAP請求消息,對SOAP響應消息壓縮。
請求的流程如下:
Client -> SOAP Request -> GzipMessageEncoder -> gzip binary -> GzipWebSericeFilter -> SOAP Request -> CXF
響應的流程如下:
CXF -> SOAP Response -> GzipWebServiceFilter -> gzip binary -> GzipMessageEncoder -> SOAP Response -> Client
其中.NET的WCF的GzipMessageEncoder是參照WCF的Samples, 下載解壓后路徑WF_WCF_Samples\WCF\Extensibility\MessageEncoder\Compression
客戶端
下面先來看一下客戶端部分的代碼:
GZipMessageEncoderFactory.cs 這文件主要是提供GZipMessageEncoder,在里面通過重寫ReadMessage和WriteMessage方法來實現壓縮和解壓縮。 實際壓縮和解壓處理是使用GZipStream實現的。
namespace?ConsoleApplication2
{
????//This?class?is?used?to?create?the?custom?encoder?(GZipMessageEncoder)
????internal?class?GZipMessageEncoderFactory?:?MessageEncoderFactory
????{
????????readonly?MessageEncoder?_encoder;
????????//The?GZip?encoder?wraps?an?inner?encoder
????????//We?require?a?factory?to?be?passed?in?that?will?create?this?inner?encoder
????????public?GZipMessageEncoderFactory(MessageEncoderFactory?messageEncoderFactory)
????????{
????????????if?(messageEncoderFactory?==?null)
????????????????throw?new?ArgumentNullException("messageEncoderFactory",?"A?valid?message?encoder?factory?must?be?passed?to?the?GZipEncoder");
????????????_encoder?=?new?GZipMessageEncoder(messageEncoderFactory.Encoder);
????????}
????????
????????//The?service?framework?uses?this?property?to?obtain?an?encoder?from?this?encoder?factory
????????public?override?MessageEncoder?Encoder
????????{
????????????get?{?return?_encoder;?}
????????}
????????public?override?MessageVersion?MessageVersion
????????{
????????????get?{?return?_encoder.MessageVersion;?}
????????}
????????//This?is?the?actual?GZip?encoder
????????class?GZipMessageEncoder?:?MessageEncoder
????????{
????????????private?const?string?GZipMediaType?=?"application/x-gzip";
????????????private?const?string?GZipContentType?=?GZipMediaType?+?";?charset=utf-8";
????????????//This?implementation?wraps?an?inner?encoder?that?actually?converts?a?WCF?Message
????????????//into?textual?XML,?binary?XML?or?some?other?format.?This?implementation?then?compresses?the?results.
????????????//The?opposite?happens?when?reading?messages.
????????????//This?member?stores?this?inner?encoder.
????????????readonly?MessageEncoder?_innerEncoder;
????????????//We?require?an?inner?encoder?to?be?supplied?(see?comment?above)
????????????internal?GZipMessageEncoder(MessageEncoder?messageEncoder)
????????????{
????????????????if?(messageEncoder?==?null)
????????????????????throw?new?ArgumentNullException("messageEncoder",?"A?valid?message?encoder?must?be?passed?to?the?GZipEncoder");
????????????????_innerEncoder?=?messageEncoder;
????????????}
????????????public?override?string?ContentType
????????????{
????????????????get?{?return?GZipContentType;?}
????????????}
????????????public?override?string?MediaType
????????????{
????????????????get?{?return?GZipMediaType;?}
????????????}
????????????//SOAP?version?to?use?-?we?delegate?to?the?inner?encoder?for?this
????????????public?override?MessageVersion?MessageVersion
????????????{
????????????????get?{?return?_innerEncoder.MessageVersion;?}
????????????}
????????????public?override?bool?IsContentTypeSupported(string?contentType)
????????????{
????????????????return?contentType.StartsWith(GZipMediaType,?StringComparison.OrdinalIgnoreCase)?||?contentType.StartsWith("text/xml",?StringComparison.OrdinalIgnoreCase);
????????????}
????????????//Helper?method?to?compress?an?array?of?bytes
????????????static?ArraySegment<byte>?CompressBuffer(ArraySegment<byte>?buffer,?BufferManager?bufferManager,?int?messageOffset)
????????????{
????????????????var?memoryStream?=?new?MemoryStream();
????????????????memoryStream.Write(buffer.Array,?0,?messageOffset);
????????????????using?(var?gzStream?=?new?GZipStream(memoryStream,?CompressionMode.Compress,?true))
????????????????{
????????????????????gzStream.Write(buffer.Array,?messageOffset,?buffer.Count);
????????????????}
????????????????var?compressedBytes?=?memoryStream.ToArray();
????????????????var?bufferedBytes?=?bufferManager.TakeBuffer(compressedBytes.Length);
????????????????Array.Copy(compressedBytes,?0,?bufferedBytes,?0,?compressedBytes.Length);
????????????????bufferManager.ReturnBuffer(buffer.Array);
????????????????var?byteArray?=?new?ArraySegment<byte>(bufferedBytes,?messageOffset,?bufferedBytes.Length?-?messageOffset);
????????????????return?byteArray;
????????????}
????????????//Helper?method?to?decompress?an?array?of?bytes
????????????static?ArraySegment<byte>?DecompressBuffer(ArraySegment<byte>?buffer,?BufferManager?bufferManager)
????????????{
????????????????var?memoryStream?=?new?MemoryStream(buffer.Array,?buffer.Offset,?buffer.Count?-?buffer.Offset);
????????????????var?decompressedStream?=?new?MemoryStream();
????????????????const?int?blockSize?=?1024;
????????????????byte[]?tempBuffer?=?bufferManager.TakeBuffer(blockSize);
????????????????using?(var?gzStream?=?new?GZipStream(memoryStream,?CompressionMode.Decompress))
????????????????{
????????????????????while?(true)
????????????????????{
????????????????????????var?bytesRead?=?gzStream.Read(tempBuffer,?0,?blockSize);
????????????????????????if?(bytesRead?==?0)
????????????????????????????break;
????????????????????????decompressedStream.Write(tempBuffer,?0,?bytesRead);
????????????????????}
????????????????}
????????????????bufferManager.ReturnBuffer(tempBuffer);
????????????????var?decompressedBytes?=?decompressedStream.ToArray();
????????????????var?bufferManagerBuffer?=?bufferManager.TakeBuffer(decompressedBytes.Length?+?buffer.Offset);
????????????????Array.Copy(buffer.Array,?0,?bufferManagerBuffer,?0,?buffer.Offset);
????????????????Array.Copy(decompressedBytes,?0,?bufferManagerBuffer,?buffer.Offset,?decompressedBytes.Length);
????????????????var?byteArray?=?new?ArraySegment<byte>(bufferManagerBuffer,?buffer.Offset,?decompressedBytes.Length);
????????????????bufferManager.ReturnBuffer(buffer.Array);
????????????????return?byteArray;
????????????}
????????????//One?of?the?two?main?entry?points?into?the?encoder.?Called?by?WCF?to?encode?a?Message?into?a?buffered?byte?array.
????????????public?override?ArraySegment<byte>?WriteMessage(Message?message,?int?maxMessageSize,?BufferManager?bufferManager,?int?messageOffset)
????????????{
????????????????//Use?the?inner?encoder?to?encode?a?Message?into?a?buffered?byte?array
????????????????ArraySegment<byte>?buffer?=?_innerEncoder.WriteMessage(message,?maxMessageSize,?bufferManager,?messageOffset);
????????????????//Compress?the?resulting?byte?array
????????????????return?CompressBuffer(buffer,?bufferManager,?messageOffset);
????????????}
????????????public?override?Message?ReadMessage(Stream?stream,?int?maxSizeOfHeaders,?string?contentType)
????????????{
????????????????var?gzStream?=?new?GZipStream(stream,?CompressionMode.Decompress,?true);
????????????????return?_innerEncoder.ReadMessage(gzStream,?maxSizeOfHeaders);
????????????}
????????????public?override?Message?ReadMessage(ArraySegment<byte>?buffer,?BufferManager?bufferManager,?string?contentType)
????????????{
????????????????//Decompress?the?buffer
????????????????ArraySegment<byte>?decompressedBuffer?=?DecompressBuffer(buffer,?bufferManager);
????????????????//Use?the?inner?encoder?to?decode?the?decompressed?buffer
????????????????Message?returnMessage?=?_innerEncoder.ReadMessage(decompressedBuffer,?bufferManager);
????????????????returnMessage.Properties.Encoder?=?this;
????????????????return?returnMessage;
????????????}
????????????public?override?void?WriteMessage(Message?message,?Stream?stream)
????????????{
????????????????using?(var?gzStream?=?new?GZipStream(stream,?CompressionMode.Compress,?true))
????????????????{
????????????????????_innerEncoder.WriteMessage(message,?gzStream);
????????????????}
????????????????//?innerEncoder.WriteMessage(message,?gzStream)?depends?on?that?it?can?flush?data?by?flushing?
????????????????//?the?stream?passed?in,?but?the?implementation?of?GZipStream.Flush?will?not?flush?underlying
????????????????//?stream,?so?we?need?to?flush?here.
????????????????stream.Flush();
????????????}
????????}
????}
}
{
????//This?class?is?used?to?create?the?custom?encoder?(GZipMessageEncoder)
????internal?class?GZipMessageEncoderFactory?:?MessageEncoderFactory
????{
????????readonly?MessageEncoder?_encoder;
????????//The?GZip?encoder?wraps?an?inner?encoder
????????//We?require?a?factory?to?be?passed?in?that?will?create?this?inner?encoder
????????public?GZipMessageEncoderFactory(MessageEncoderFactory?messageEncoderFactory)
????????{
????????????if?(messageEncoderFactory?==?null)
????????????????throw?new?ArgumentNullException("messageEncoderFactory",?"A?valid?message?encoder?factory?must?be?passed?to?the?GZipEncoder");
????????????_encoder?=?new?GZipMessageEncoder(messageEncoderFactory.Encoder);
????????}
????????
????????//The?service?framework?uses?this?property?to?obtain?an?encoder?from?this?encoder?factory
????????public?override?MessageEncoder?Encoder
????????{
????????????get?{?return?_encoder;?}
????????}
????????public?override?MessageVersion?MessageVersion
????????{
????????????get?{?return?_encoder.MessageVersion;?}
????????}
????????//This?is?the?actual?GZip?encoder
????????class?GZipMessageEncoder?:?MessageEncoder
????????{
????????????private?const?string?GZipMediaType?=?"application/x-gzip";
????????????private?const?string?GZipContentType?=?GZipMediaType?+?";?charset=utf-8";
????????????//This?implementation?wraps?an?inner?encoder?that?actually?converts?a?WCF?Message
????????????//into?textual?XML,?binary?XML?or?some?other?format.?This?implementation?then?compresses?the?results.
????????????//The?opposite?happens?when?reading?messages.
????????????//This?member?stores?this?inner?encoder.
????????????readonly?MessageEncoder?_innerEncoder;
????????????//We?require?an?inner?encoder?to?be?supplied?(see?comment?above)
????????????internal?GZipMessageEncoder(MessageEncoder?messageEncoder)
????????????{
????????????????if?(messageEncoder?==?null)
????????????????????throw?new?ArgumentNullException("messageEncoder",?"A?valid?message?encoder?must?be?passed?to?the?GZipEncoder");
????????????????_innerEncoder?=?messageEncoder;
????????????}
????????????public?override?string?ContentType
????????????{
????????????????get?{?return?GZipContentType;?}
????????????}
????????????public?override?string?MediaType
????????????{
????????????????get?{?return?GZipMediaType;?}
????????????}
????????????//SOAP?version?to?use?-?we?delegate?to?the?inner?encoder?for?this
????????????public?override?MessageVersion?MessageVersion
????????????{
????????????????get?{?return?_innerEncoder.MessageVersion;?}
????????????}
????????????public?override?bool?IsContentTypeSupported(string?contentType)
????????????{
????????????????return?contentType.StartsWith(GZipMediaType,?StringComparison.OrdinalIgnoreCase)?||?contentType.StartsWith("text/xml",?StringComparison.OrdinalIgnoreCase);
????????????}
????????????//Helper?method?to?compress?an?array?of?bytes
????????????static?ArraySegment<byte>?CompressBuffer(ArraySegment<byte>?buffer,?BufferManager?bufferManager,?int?messageOffset)
????????????{
????????????????var?memoryStream?=?new?MemoryStream();
????????????????memoryStream.Write(buffer.Array,?0,?messageOffset);
????????????????using?(var?gzStream?=?new?GZipStream(memoryStream,?CompressionMode.Compress,?true))
????????????????{
????????????????????gzStream.Write(buffer.Array,?messageOffset,?buffer.Count);
????????????????}
????????????????var?compressedBytes?=?memoryStream.ToArray();
????????????????var?bufferedBytes?=?bufferManager.TakeBuffer(compressedBytes.Length);
????????????????Array.Copy(compressedBytes,?0,?bufferedBytes,?0,?compressedBytes.Length);
????????????????bufferManager.ReturnBuffer(buffer.Array);
????????????????var?byteArray?=?new?ArraySegment<byte>(bufferedBytes,?messageOffset,?bufferedBytes.Length?-?messageOffset);
????????????????return?byteArray;
????????????}
????????????//Helper?method?to?decompress?an?array?of?bytes
????????????static?ArraySegment<byte>?DecompressBuffer(ArraySegment<byte>?buffer,?BufferManager?bufferManager)
????????????{
????????????????var?memoryStream?=?new?MemoryStream(buffer.Array,?buffer.Offset,?buffer.Count?-?buffer.Offset);
????????????????var?decompressedStream?=?new?MemoryStream();
????????????????const?int?blockSize?=?1024;
????????????????byte[]?tempBuffer?=?bufferManager.TakeBuffer(blockSize);
????????????????using?(var?gzStream?=?new?GZipStream(memoryStream,?CompressionMode.Decompress))
????????????????{
????????????????????while?(true)
????????????????????{
????????????????????????var?bytesRead?=?gzStream.Read(tempBuffer,?0,?blockSize);
????????????????????????if?(bytesRead?==?0)
????????????????????????????break;
????????????????????????decompressedStream.Write(tempBuffer,?0,?bytesRead);
????????????????????}
????????????????}
????????????????bufferManager.ReturnBuffer(tempBuffer);
????????????????var?decompressedBytes?=?decompressedStream.ToArray();
????????????????var?bufferManagerBuffer?=?bufferManager.TakeBuffer(decompressedBytes.Length?+?buffer.Offset);
????????????????Array.Copy(buffer.Array,?0,?bufferManagerBuffer,?0,?buffer.Offset);
????????????????Array.Copy(decompressedBytes,?0,?bufferManagerBuffer,?buffer.Offset,?decompressedBytes.Length);
????????????????var?byteArray?=?new?ArraySegment<byte>(bufferManagerBuffer,?buffer.Offset,?decompressedBytes.Length);
????????????????bufferManager.ReturnBuffer(buffer.Array);
????????????????return?byteArray;
????????????}
????????????//One?of?the?two?main?entry?points?into?the?encoder.?Called?by?WCF?to?encode?a?Message?into?a?buffered?byte?array.
????????????public?override?ArraySegment<byte>?WriteMessage(Message?message,?int?maxMessageSize,?BufferManager?bufferManager,?int?messageOffset)
????????????{
????????????????//Use?the?inner?encoder?to?encode?a?Message?into?a?buffered?byte?array
????????????????ArraySegment<byte>?buffer?=?_innerEncoder.WriteMessage(message,?maxMessageSize,?bufferManager,?messageOffset);
????????????????//Compress?the?resulting?byte?array
????????????????return?CompressBuffer(buffer,?bufferManager,?messageOffset);
????????????}
????????????public?override?Message?ReadMessage(Stream?stream,?int?maxSizeOfHeaders,?string?contentType)
????????????{
????????????????var?gzStream?=?new?GZipStream(stream,?CompressionMode.Decompress,?true);
????????????????return?_innerEncoder.ReadMessage(gzStream,?maxSizeOfHeaders);
????????????}
????????????public?override?Message?ReadMessage(ArraySegment<byte>?buffer,?BufferManager?bufferManager,?string?contentType)
????????????{
????????????????//Decompress?the?buffer
????????????????ArraySegment<byte>?decompressedBuffer?=?DecompressBuffer(buffer,?bufferManager);
????????????????//Use?the?inner?encoder?to?decode?the?decompressed?buffer
????????????????Message?returnMessage?=?_innerEncoder.ReadMessage(decompressedBuffer,?bufferManager);
????????????????returnMessage.Properties.Encoder?=?this;
????????????????return?returnMessage;
????????????}
????????????public?override?void?WriteMessage(Message?message,?Stream?stream)
????????????{
????????????????using?(var?gzStream?=?new?GZipStream(stream,?CompressionMode.Compress,?true))
????????????????{
????????????????????_innerEncoder.WriteMessage(message,?gzStream);
????????????????}
????????????????//?innerEncoder.WriteMessage(message,?gzStream)?depends?on?that?it?can?flush?data?by?flushing?
????????????????//?the?stream?passed?in,?but?the?implementation?of?GZipStream.Flush?will?not?flush?underlying
????????????????//?stream,?so?we?need?to?flush?here.
????????????????stream.Flush();
????????????}
????????}
????}
}
下面是GZipMessageEncodingBindingElement.cs 這里的GZipMessageEncodingBindingElement類是為了在app.config里添加配置項。
namespace?ConsoleApplication2
{
????//This?is?the?binding?element?that,?when?plugged?into?a?custom?binding,?will?enable?the?GZip?encoder
????public?sealed?class?GZipMessageEncodingBindingElement?
????????????????????????:?MessageEncodingBindingElement?//BindingElement
????{
????????//We?will?use?an?inner?binding?element?to?store?information?required?for?the?inner?encoder
????????MessageEncodingBindingElement?_innerBindingElement;
????????//By?default,?use?the?default?text?encoder?as?the?inner?encoder
????????public?GZipMessageEncodingBindingElement()
????????????:?this(new?TextMessageEncodingBindingElement())?{?}
????????public?GZipMessageEncodingBindingElement(MessageEncodingBindingElement?messageEncoderBindingElement)
????????{
????????????_innerBindingElement?=?messageEncoderBindingElement;
????????}
????????public?MessageEncodingBindingElement?InnerMessageEncodingBindingElement
????????{
????????????get?{?return?_innerBindingElement;?}
????????????set?{?_innerBindingElement?=?value;?}
????????}
????????//Main?entry?point?into?the?encoder?binding?element.?Called?by?WCF?to?get?the?factory?that?will?create?the
????????//message?encoder
????????public?override?MessageEncoderFactory?CreateMessageEncoderFactory()
????????{
????????????return?new?GZipMessageEncoderFactory(_innerBindingElement.CreateMessageEncoderFactory());
????????}
???????
????????public?override?MessageVersion?MessageVersion
????????{
????????????get?{?return?_innerBindingElement.MessageVersion;?}
????????????set?{?_innerBindingElement.MessageVersion?=?value;?}
????????}
????????public?override?BindingElement?Clone()
????????{
????????????return?new?GZipMessageEncodingBindingElement(_innerBindingElement);
????????}
????????public?override?T?GetProperty<T>(BindingContext?context)
????????{
????????????if?(typeof(T)?==?typeof(XmlDictionaryReaderQuotas))
????????????{
????????????????return?_innerBindingElement.GetProperty<T>(context);
????????????}
????????????return?base.GetProperty<T>(context);
????????}
????????public?override?IChannelFactory<TChannel>?BuildChannelFactory<TChannel>(BindingContext?context)
????????{
????????????if?(context?==?null)
????????????????throw?new?ArgumentNullException("context");
????????????context.BindingParameters.Add(this);
????????????return?context.BuildInnerChannelFactory<TChannel>();
????????}
????????public?override?IChannelListener<TChannel>?BuildChannelListener<TChannel>(BindingContext?context)
????????{
????????????if?(context?==?null)
????????????????throw?new?ArgumentNullException("context");
????????????context.BindingParameters.Add(this);
????????????return?context.BuildInnerChannelListener<TChannel>();
????????}
????????public?override?bool?CanBuildChannelListener<TChannel>(BindingContext?context)
????????{
????????????if?(context?==?null)
????????????????throw?new?ArgumentNullException("context");
????????????context.BindingParameters.Add(this);
????????????return?context.CanBuildInnerChannelListener<TChannel>();
????????}
????}
????//This?class?is?necessary?to?be?able?to?plug?in?the?GZip?encoder?binding?element?through
????//a?configuration?file
????public?class?GZipMessageEncodingElement?:?BindingElementExtensionElement
????{
????????//Called?by?the?WCF?to?discover?the?type?of?binding?element?this?config?section?enables
????????public?override?Type?BindingElementType
????????{
????????????get?{?return?typeof(GZipMessageEncodingBindingElement);?}
????????}
????????//The?only?property?we?need?to?configure?for?our?binding?element?is?the?type?of
????????//inner?encoder?to?use.?Here,?we?support?text?and?binary.
????????[ConfigurationProperty("innerMessageEncoding",?DefaultValue?=?"textMessageEncoding")]
????????public?string?InnerMessageEncoding
????????{
????????????get?{?return?(string)base["innerMessageEncoding"];?}
????????????set?{?base["innerMessageEncoding"]?=?value;?}
????????}
????????//The?only?property?we?need?to?configure?for?our?binding?element?is?the?type?of
????????//inner?encoder?to?use.?Here,?we?support?text?and?binary.
????????[ConfigurationProperty("messageVersion",?DefaultValue?=?"Soap12")]
????????public?string?MessageVersion
????????{
????????????get?{?return?(string)base["messageVersion"];?}
????????????set?{?base["messageVersion"]?=?value;?}
????????}
????????//Called?by?the?WCF?to?apply?the?configuration?settings?(the?property?above)?to?the?binding?element
????????public?override?void?ApplyConfiguration(BindingElement?bindingElement)
????????{
????????????var?binding?=?(GZipMessageEncodingBindingElement)bindingElement;
????????????PropertyInformationCollection?propertyInfo?=?ElementInformation.Properties;
????????????var?propertyInformation?=?propertyInfo["innerMessageEncoding"];
????????????if?(propertyInformation?==?null?||?propertyInformation.ValueOrigin?==?PropertyValueOrigin.Default)?return;
????????????var?version?=?System.ServiceModel.Channels.MessageVersion.Soap12;
????????????if?("Soap11"?==?MessageVersion)
????????????{
????????????????version?=?System.ServiceModel.Channels.MessageVersion.Soap11;
????????????}
????????????switch?(InnerMessageEncoding)
????????????{
????????????????case?"textMessageEncoding":
????????????????????binding.InnerMessageEncodingBindingElement?=?new?TextMessageEncodingBindingElement()?{?MessageVersion?=?version?};
????????????????????break;
????????????????case?"binaryMessageEncoding":
????????????????????binding.InnerMessageEncodingBindingElement?=?new?BinaryMessageEncodingBindingElement();
????????????????????break;
????????????}
????????}
????????//Called?by?the?WCF?to?create?the?binding?element
????????protected?override?BindingElement?CreateBindingElement()
????????{
????????????var?bindingElement?=?new?GZipMessageEncodingBindingElement();
????????????ApplyConfiguration(bindingElement);
????????????return?bindingElement;
????????}
????}
}
{
????//This?is?the?binding?element?that,?when?plugged?into?a?custom?binding,?will?enable?the?GZip?encoder
????public?sealed?class?GZipMessageEncodingBindingElement?
????????????????????????:?MessageEncodingBindingElement?//BindingElement
????{
????????//We?will?use?an?inner?binding?element?to?store?information?required?for?the?inner?encoder
????????MessageEncodingBindingElement?_innerBindingElement;
????????//By?default,?use?the?default?text?encoder?as?the?inner?encoder
????????public?GZipMessageEncodingBindingElement()
????????????:?this(new?TextMessageEncodingBindingElement())?{?}
????????public?GZipMessageEncodingBindingElement(MessageEncodingBindingElement?messageEncoderBindingElement)
????????{
????????????_innerBindingElement?=?messageEncoderBindingElement;
????????}
????????public?MessageEncodingBindingElement?InnerMessageEncodingBindingElement
????????{
????????????get?{?return?_innerBindingElement;?}
????????????set?{?_innerBindingElement?=?value;?}
????????}
????????//Main?entry?point?into?the?encoder?binding?element.?Called?by?WCF?to?get?the?factory?that?will?create?the
????????//message?encoder
????????public?override?MessageEncoderFactory?CreateMessageEncoderFactory()
????????{
????????????return?new?GZipMessageEncoderFactory(_innerBindingElement.CreateMessageEncoderFactory());
????????}
???????
????????public?override?MessageVersion?MessageVersion
????????{
????????????get?{?return?_innerBindingElement.MessageVersion;?}
????????????set?{?_innerBindingElement.MessageVersion?=?value;?}
????????}
????????public?override?BindingElement?Clone()
????????{
????????????return?new?GZipMessageEncodingBindingElement(_innerBindingElement);
????????}
????????public?override?T?GetProperty<T>(BindingContext?context)
????????{
????????????if?(typeof(T)?==?typeof(XmlDictionaryReaderQuotas))
????????????{
????????????????return?_innerBindingElement.GetProperty<T>(context);
????????????}
????????????return?base.GetProperty<T>(context);
????????}
????????public?override?IChannelFactory<TChannel>?BuildChannelFactory<TChannel>(BindingContext?context)
????????{
????????????if?(context?==?null)
????????????????throw?new?ArgumentNullException("context");
????????????context.BindingParameters.Add(this);
????????????return?context.BuildInnerChannelFactory<TChannel>();
????????}
????????public?override?IChannelListener<TChannel>?BuildChannelListener<TChannel>(BindingContext?context)
????????{
????????????if?(context?==?null)
????????????????throw?new?ArgumentNullException("context");
????????????context.BindingParameters.Add(this);
????????????return?context.BuildInnerChannelListener<TChannel>();
????????}
????????public?override?bool?CanBuildChannelListener<TChannel>(BindingContext?context)
????????{
????????????if?(context?==?null)
????????????????throw?new?ArgumentNullException("context");
????????????context.BindingParameters.Add(this);
????????????return?context.CanBuildInnerChannelListener<TChannel>();
????????}
????}
????//This?class?is?necessary?to?be?able?to?plug?in?the?GZip?encoder?binding?element?through
????//a?configuration?file
????public?class?GZipMessageEncodingElement?:?BindingElementExtensionElement
????{
????????//Called?by?the?WCF?to?discover?the?type?of?binding?element?this?config?section?enables
????????public?override?Type?BindingElementType
????????{
????????????get?{?return?typeof(GZipMessageEncodingBindingElement);?}
????????}
????????//The?only?property?we?need?to?configure?for?our?binding?element?is?the?type?of
????????//inner?encoder?to?use.?Here,?we?support?text?and?binary.
????????[ConfigurationProperty("innerMessageEncoding",?DefaultValue?=?"textMessageEncoding")]
????????public?string?InnerMessageEncoding
????????{
????????????get?{?return?(string)base["innerMessageEncoding"];?}
????????????set?{?base["innerMessageEncoding"]?=?value;?}
????????}
????????//The?only?property?we?need?to?configure?for?our?binding?element?is?the?type?of
????????//inner?encoder?to?use.?Here,?we?support?text?and?binary.
????????[ConfigurationProperty("messageVersion",?DefaultValue?=?"Soap12")]
????????public?string?MessageVersion
????????{
????????????get?{?return?(string)base["messageVersion"];?}
????????????set?{?base["messageVersion"]?=?value;?}
????????}
????????//Called?by?the?WCF?to?apply?the?configuration?settings?(the?property?above)?to?the?binding?element
????????public?override?void?ApplyConfiguration(BindingElement?bindingElement)
????????{
????????????var?binding?=?(GZipMessageEncodingBindingElement)bindingElement;
????????????PropertyInformationCollection?propertyInfo?=?ElementInformation.Properties;
????????????var?propertyInformation?=?propertyInfo["innerMessageEncoding"];
????????????if?(propertyInformation?==?null?||?propertyInformation.ValueOrigin?==?PropertyValueOrigin.Default)?return;
????????????var?version?=?System.ServiceModel.Channels.MessageVersion.Soap12;
????????????if?("Soap11"?==?MessageVersion)
????????????{
????????????????version?=?System.ServiceModel.Channels.MessageVersion.Soap11;
????????????}
????????????switch?(InnerMessageEncoding)
????????????{
????????????????case?"textMessageEncoding":
????????????????????binding.InnerMessageEncodingBindingElement?=?new?TextMessageEncodingBindingElement()?{?MessageVersion?=?version?};
????????????????????break;
????????????????case?"binaryMessageEncoding":
????????????????????binding.InnerMessageEncodingBindingElement?=?new?BinaryMessageEncodingBindingElement();
????????????????????break;
????????????}
????????}
????????//Called?by?the?WCF?to?create?the?binding?element
????????protected?override?BindingElement?CreateBindingElement()
????????{
????????????var?bindingElement?=?new?GZipMessageEncodingBindingElement();
????????????ApplyConfiguration(bindingElement);
????????????return?bindingElement;
????????}
????}
}
然后我們就可以把這個GZipMessageEncodingElement配置到app.config里了
<?xml?version="1.0"?encoding="utf-8"??>
<configuration>
??<system.serviceModel>
????<extensions>
??????<bindingElementExtensions>
????????<add?name="gzipMessageEncoding"?type="ConsoleApplication2.GZipMessageEncodingElement,ConsoleApplication2"?/>
??????</bindingElementExtensions>
????</extensions>
????<bindings>
??????<customBinding>
????????<binding?name="countServiceSoapBinding">
??????????<gzipMessageEncoding?innerMessageEncoding="textMessageEncoding"?messageVersion="Soap11"/>
??????????<httpTransport?manualAddressing="false"
?????????????????????????authenticationScheme="Anonymous"
?????????????????????????bypassProxyOnLocal="false"
?????????????????????????hostNameComparisonMode="StrongWildcard"
?????????????????????????proxyAuthenticationScheme="Anonymous"
?????????????????????????realm=""
?????????????????????????useDefaultWebProxy="true"?/>
????????</binding>
??????</customBinding>
????</bindings>
????<client>
??????<endpoint?address="http://192.168.2.3:8080/binder/services/countService"
??????????binding="customBinding"?bindingConfiguration="countServiceSoapBinding"
??????????contract="ServiceReference1.HolidayService"?name="HolidayServiceImplPort"?/>
????</client>
??</system.serviceModel>
</configuration>
<configuration>
??<system.serviceModel>
????<extensions>
??????<bindingElementExtensions>
????????<add?name="gzipMessageEncoding"?type="ConsoleApplication2.GZipMessageEncodingElement,ConsoleApplication2"?/>
??????</bindingElementExtensions>
????</extensions>
????<bindings>
??????<customBinding>
????????<binding?name="countServiceSoapBinding">
??????????<gzipMessageEncoding?innerMessageEncoding="textMessageEncoding"?messageVersion="Soap11"/>
??????????<httpTransport?manualAddressing="false"
?????????????????????????authenticationScheme="Anonymous"
?????????????????????????bypassProxyOnLocal="false"
?????????????????????????hostNameComparisonMode="StrongWildcard"
?????????????????????????proxyAuthenticationScheme="Anonymous"
?????????????????????????realm=""
?????????????????????????useDefaultWebProxy="true"?/>
????????</binding>
??????</customBinding>
????</bindings>
????<client>
??????<endpoint?address="http://192.168.2.3:8080/binder/services/countService"
??????????binding="customBinding"?bindingConfiguration="countServiceSoapBinding"
??????????contract="ServiceReference1.HolidayService"?name="HolidayServiceImplPort"?/>
????</client>
??</system.serviceModel>
</configuration>
客戶端最后的部分就是調用webservice, 這里的壓縮和解壓對于調用者和陪調用者是透明的。也就是同沒有壓縮和解壓之前的使用方法一樣。
namespace?ConsoleApplication2
{
????class?Program
????{
????????static?void?Main(string[]?args)
????????{
????????????try
????????????{
????????????????var?service?=?new?ServiceReference1.HolidayServiceClient();
????????????????var?text?=File.ReadAllText("c:\\words");
????????????????var?len?=?service.countText(text);
????????????????Console.WriteLine("lenght?=?{0}",?len);
???????????????
????????????}
????????????catch?(Exception?e)
????????????{
????????????????Console.WriteLine(e.Message);
????????????????Console.WriteLine(e.StackTrace);
????????????}
????????????Console.Read();
????????}
????}
}
{
????class?Program
????{
????????static?void?Main(string[]?args)
????????{
????????????try
????????????{
????????????????var?service?=?new?ServiceReference1.HolidayServiceClient();
????????????????var?text?=File.ReadAllText("c:\\words");
????????????????var?len?=?service.countText(text);
????????????????Console.WriteLine("lenght?=?{0}",?len);
???????????????
????????????}
????????????catch?(Exception?e)
????????????{
????????????????Console.WriteLine(e.Message);
????????????????Console.WriteLine(e.StackTrace);
????????????}
????????????Console.Read();
????????}
????}
}
服務端
服務端是一個Filter,和HttpServletRequest和HttpServletResponse的包裝類。
入口:GzipWebServiceFilter.java
/**
?*?把使用Gzip壓縮的SOAP消息解壓縮。
?*?@author?matianyi
?*
?*/
public?class?GzipWebServiceFilter?implements?Filter?{
????public?static?final?String?CONTENT_TYPE?=?"application/x-gzip";
????public?static?final?String?CONTENT_ENCODING?=?"utf-8";
????@Override
????public?void?init(FilterConfig?filterConfig)?throws?ServletException?{
????????//?TODO?Auto-generated?method?stub
????}
????@SuppressWarnings("unchecked")
????@Override
????public?void?doFilter(ServletRequest?request,?ServletResponse?response,
????????????FilterChain?chain)?throws?IOException,?ServletException?{
????????
????????HttpServletRequest?req?=?(HttpServletRequest)?request;
????????HttpServletResponse?resp?=?(HttpServletResponse)?response;
????????
????????if(req.getContentType()?==?null?||?!req.getContentType().startsWith(CONTENT_TYPE)){
????????????chain.doFilter(request,?response);
????????}?else?{
????????????chain.doFilter(new?GzipHttpServletRequestWrapper(req),?new?GzipHttpServletResponseWrapper(resp));
????????}
????}
????@Override
????public?void?destroy()?{
????????//?TODO?Auto-generated?method?stub
????}
}
?*?把使用Gzip壓縮的SOAP消息解壓縮。
?*?@author?matianyi
?*
?*/
public?class?GzipWebServiceFilter?implements?Filter?{
????public?static?final?String?CONTENT_TYPE?=?"application/x-gzip";
????public?static?final?String?CONTENT_ENCODING?=?"utf-8";
????@Override
????public?void?init(FilterConfig?filterConfig)?throws?ServletException?{
????????//?TODO?Auto-generated?method?stub
????}
????@SuppressWarnings("unchecked")
????@Override
????public?void?doFilter(ServletRequest?request,?ServletResponse?response,
????????????FilterChain?chain)?throws?IOException,?ServletException?{
????????
????????HttpServletRequest?req?=?(HttpServletRequest)?request;
????????HttpServletResponse?resp?=?(HttpServletResponse)?response;
????????
????????if(req.getContentType()?==?null?||?!req.getContentType().startsWith(CONTENT_TYPE)){
????????????chain.doFilter(request,?response);
????????}?else?{
????????????chain.doFilter(new?GzipHttpServletRequestWrapper(req),?new?GzipHttpServletResponseWrapper(resp));
????????}
????}
????@Override
????public?void?destroy()?{
????????//?TODO?Auto-generated?method?stub
????}
}
這里就是判斷contentType,如果是gzip的就用GzipHttpServletRequestWrapper和GzipHttpServletResponseWrapper包裝原始的Request和Response以實現壓縮和解壓縮。
GzipHttpServletRequestWrapper
public?class?GzipHttpServletRequestWrapper?extends?HttpServletRequestWrapper?{
????public?static?final?String?CONTNET_TYPE_SOAP_1_2?=?"application/soap+xml";
????public?static?final?String?CONTNET_TYPE_SOAP_1_1?=?"text/xml";
????public?GzipHttpServletRequestWrapper(HttpServletRequest?request)?{
????????super(request);
????}
????@Override
????public?ServletInputStream?getInputStream()?throws?IOException?{
????????return?new?GzipServletInputStream(super.getInputStream());
????}
????@Override
????public?String?getContentType()?{
????????return?CONTNET_TYPE_SOAP_1_2;
????}
????@Override
????public?String?getHeader(String?name)?{
????????if?("content-type".equalsIgnoreCase(name))?{
????????????return?getContentType();
????????}?else?{
????????????return?super.getHeader(name);
????????}
????}
}
class?GzipServletInputStream?extends?ServletInputStream?{
????private?GZIPInputStream?delegate;
????public?GzipServletInputStream(ServletInputStream?servletInputStream)
????????????throws?IOException?{
????????super();
????????this.delegate?=?new?GZIPInputStream(servletInputStream);
????}
????@Override
????public?int?read()?throws?IOException?{
????????return?delegate.read();
????}
}
????public?static?final?String?CONTNET_TYPE_SOAP_1_2?=?"application/soap+xml";
????public?static?final?String?CONTNET_TYPE_SOAP_1_1?=?"text/xml";
????public?GzipHttpServletRequestWrapper(HttpServletRequest?request)?{
????????super(request);
????}
????@Override
????public?ServletInputStream?getInputStream()?throws?IOException?{
????????return?new?GzipServletInputStream(super.getInputStream());
????}
????@Override
????public?String?getContentType()?{
????????return?CONTNET_TYPE_SOAP_1_2;
????}
????@Override
????public?String?getHeader(String?name)?{
????????if?("content-type".equalsIgnoreCase(name))?{
????????????return?getContentType();
????????}?else?{
????????????return?super.getHeader(name);
????????}
????}
}
class?GzipServletInputStream?extends?ServletInputStream?{
????private?GZIPInputStream?delegate;
????public?GzipServletInputStream(ServletInputStream?servletInputStream)
????????????throws?IOException?{
????????super();
????????this.delegate?=?new?GZIPInputStream(servletInputStream);
????}
????@Override
????public?int?read()?throws?IOException?{
????????return?delegate.read();
????}
}
GzipHttpServletResponseWrapper
public?class?GzipHttpServletResponseWrapper?extends?HttpServletResponseWrapper?{
????public?GzipHttpServletResponseWrapper(HttpServletResponse?response)?{
????????super(response);
????}
????@Override
????public?ServletOutputStream?getOutputStream()?throws?IOException?{
????????return?new?GzipServletOutputStream(super.getOutputStream());
????}
????@Override
????public?void?setCharacterEncoding(String?charset)?{
????????super.setCharacterEncoding(GzipWebServiceFilter.CONTENT_ENCODING);
????}
????@Override
????public?void?setContentType(String?type)?{
????????super.setContentType(GzipWebServiceFilter.CONTENT_TYPE?+?";?charset="?+?GzipWebServiceFilter.CONTENT_ENCODING);
????}
????
}
class?GzipServletOutputStream?extends?ServletOutputStream{
????private?GZIPOutputStream?delegate;
????public?GzipServletOutputStream(ServletOutputStream?servletOutputStream)
????????????throws?IOException?{
????????super();
????????this.delegate?=?new?GZIPOutputStream(servletOutputStream);
????}
????
????
????@Override
????public?void?write(int?b)?throws?IOException?{
????????System.out.print((char)b);
????????delegate.write(b);
????}
????public?void?close()?throws?IOException?{
????????delegate.close();
????}
????public?void?flush()?throws?IOException?{
????????delegate.flush();
????}
????public?void?write(byte[]?buf,?int?off,?int?len)?throws?IOException?{
????????delegate.write(buf,?off,?len);
????}
????public?void?write(byte[]?b)?throws?IOException?{
????????delegate.write(b);
????}
????
????
}
這里做的主要事情就是在Resquest的getInputStream和Response的getOutputStream是返回一個擁有GZip功能的Stream,來代替原始的Stream。通過原始的Stream仍然是最終的輸入和輸出源。
????public?GzipHttpServletResponseWrapper(HttpServletResponse?response)?{
????????super(response);
????}
????@Override
????public?ServletOutputStream?getOutputStream()?throws?IOException?{
????????return?new?GzipServletOutputStream(super.getOutputStream());
????}
????@Override
????public?void?setCharacterEncoding(String?charset)?{
????????super.setCharacterEncoding(GzipWebServiceFilter.CONTENT_ENCODING);
????}
????@Override
????public?void?setContentType(String?type)?{
????????super.setContentType(GzipWebServiceFilter.CONTENT_TYPE?+?";?charset="?+?GzipWebServiceFilter.CONTENT_ENCODING);
????}
????
}
class?GzipServletOutputStream?extends?ServletOutputStream{
????private?GZIPOutputStream?delegate;
????public?GzipServletOutputStream(ServletOutputStream?servletOutputStream)
????????????throws?IOException?{
????????super();
????????this.delegate?=?new?GZIPOutputStream(servletOutputStream);
????}
????
????
????@Override
????public?void?write(int?b)?throws?IOException?{
????????System.out.print((char)b);
????????delegate.write(b);
????}
????public?void?close()?throws?IOException?{
????????delegate.close();
????}
????public?void?flush()?throws?IOException?{
????????delegate.flush();
????}
????public?void?write(byte[]?buf,?int?off,?int?len)?throws?IOException?{
????????delegate.write(buf,?off,?len);
????}
????public?void?write(byte[]?b)?throws?IOException?{
????????delegate.write(b);
????}
????
????
}
然后在web.xml中把這個Filter作用于原來的WebService的Servlet
web.xml
<?xml?version="1.0"?encoding="UTF-8"?>
<web-app?version="2.5"?xmlns="http://java.sun.com/xml/ns/javaee"
????xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
????xsi:schemaLocation="http://java.sun.com/xml/ns/javaee?http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
????<!--?The?definition?of?the?Root?Spring?Container?shared?by?all?Servlets?and?Filters?-->
????<context-param>
????????<param-name>contextConfigLocation</param-name>
????????<param-value>/WEB-INF/spring/root-context.xml</param-value>
????</context-param>
????
????<!--?Creates?the?Spring?Container?shared?by?all?Servlets?and?Filters?-->
????<listener>
????????<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
????</listener>
????
????<filter>
????????<filter-name>GzipWebServiceFilter</filter-name>
????????<filter-class>com.cccis.ws.GzipWebServiceFilter</filter-class>
????</filter>
????
????<filter-mapping>
????????<filter-name>GzipWebServiceFilter</filter-name>
????????<url-pattern>/services/*</url-pattern>
????</filter-mapping>
????<servlet>
????????<description>Apache?CXF?Endpoint</description>
????????<servlet-name>cxf</servlet-name>
????????<servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
????????<load-on-startup>1</load-on-startup>
????</servlet>
????<servlet-mapping>
????????<servlet-name>cxf</servlet-name>
????????<url-pattern>/services/*</url-pattern>
????</servlet-mapping>
</web-app>
<web-app?version="2.5"?xmlns="http://java.sun.com/xml/ns/javaee"
????xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
????xsi:schemaLocation="http://java.sun.com/xml/ns/javaee?http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
????<!--?The?definition?of?the?Root?Spring?Container?shared?by?all?Servlets?and?Filters?-->
????<context-param>
????????<param-name>contextConfigLocation</param-name>
????????<param-value>/WEB-INF/spring/root-context.xml</param-value>
????</context-param>
????
????<!--?Creates?the?Spring?Container?shared?by?all?Servlets?and?Filters?-->
????<listener>
????????<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
????</listener>
????
????<filter>
????????<filter-name>GzipWebServiceFilter</filter-name>
????????<filter-class>com.cccis.ws.GzipWebServiceFilter</filter-class>
????</filter>
????
????<filter-mapping>
????????<filter-name>GzipWebServiceFilter</filter-name>
????????<url-pattern>/services/*</url-pattern>
????</filter-mapping>
????<servlet>
????????<description>Apache?CXF?Endpoint</description>
????????<servlet-name>cxf</servlet-name>
????????<servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
????????<load-on-startup>1</load-on-startup>
????</servlet>
????<servlet-mapping>
????????<servlet-name>cxf</servlet-name>
????????<url-pattern>/services/*</url-pattern>
????</servlet-mapping>
</web-app>
webservice的配置和cxf原來的一樣
<?xml?version="1.0"?encoding="UTF-8"?>
<beans?xmlns="http://www.springframework.org/schema/beans"
????xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
????xmlns:context="http://www.springframework.org/schema/context"
????xmlns:jaxws="http://cxf.apache.org/jaxws"
????xsi:schemaLocation="http://www.springframework.org/schema/beans?http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
???????http://www.springframework.org/schema/context?http://www.springframework.org/schema/context/spring-context.xsd
???????http://cxf.apache.org/jaxws?http://cxf.apache.org/schemas/jaxws.xsd">
????
????<import?resource="classpath:META-INF/cxf/cxf.xml"?/>
????<import?resource="classpath:META-INF/cxf/cxf-servlet.xml"?/>
????
????<bean?id="countServiceImpl"?class="com.cccis.ws.HolidayServiceImpl"?/>
????<jaxws:endpoint?
??????id="countService"?
??????implementor="#countServiceImpl"?
??????serviceName="countService"
??????address="/countService"?/>
??????
</beans>
如果你想看一下實際的HTTP請求和響應是什么樣子的可以用Fiddler Web Debugger來查看
<beans?xmlns="http://www.springframework.org/schema/beans"
????xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
????xmlns:context="http://www.springframework.org/schema/context"
????xmlns:jaxws="http://cxf.apache.org/jaxws"
????xsi:schemaLocation="http://www.springframework.org/schema/beans?http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
???????http://www.springframework.org/schema/context?http://www.springframework.org/schema/context/spring-context.xsd
???????http://cxf.apache.org/jaxws?http://cxf.apache.org/schemas/jaxws.xsd">
????
????<import?resource="classpath:META-INF/cxf/cxf.xml"?/>
????<import?resource="classpath:META-INF/cxf/cxf-servlet.xml"?/>
????
????<bean?id="countServiceImpl"?class="com.cccis.ws.HolidayServiceImpl"?/>
????<jaxws:endpoint?
??????id="countService"?
??????implementor="#countServiceImpl"?
??????serviceName="countService"
??????address="/countService"?/>
??????
</beans>

本文的源代碼在附件中。
本文的方案沒有在最終的被用于生產環境,一個原因是比較復雜,另外一個是服務器在對大XML進行unmarshal的效率并不高。單本文的方案的好處就是不用對原有的webservice接口和實現進行修改。 最后在實際場景用我們使用MTOM來解決問題的, 后面我還會寫一篇文章來介紹這個方法。
source.zip