1. 程式人生 > >通過GZIP優化效能

通過GZIP優化效能

              原創文章,轉載請註明

              gzip為一種壓縮技術,在網路http傳輸中得到應用。gzip需要web容器,瀏覽器的支援。

              看一下效果

              壓縮前:

              

              壓縮後:

 

             這裡的時間不需要糾結,開發環境在本機,這裡的效能損耗主要在cpu上,也就是壓縮時消耗的cpu,而且本機還跑了其他東西,不同時刻的環境不太一樣。

      1、tomcat配置

               tomcat中使用gzip需要進行配置,在server.xml中,在Connector標籤中加入如下屬性

compression="on"
compressionMinSize="2048"
noCompressionUserAgents="gozilla,traviata"
compressableMimeType="text/html,text/css.text/javascript"

               compression:指定是否開啟壓縮

               compressionMinSize:表示小於該值進行壓縮,單位為Byte

               noCompressionUserAgents:表示不進行壓縮的瀏覽器

               compressableMimeType:表示哪些格式的檔案需要被壓縮

               注意:圖片不要進行壓縮,因為圖片完全可以在專案開發中使用壓縮後的圖片。這樣避免了壓縮對於CPU的消耗

      2、程式碼

              除了進行tomcat配置之外,還需要對請求寫一個filter進行壓縮。

        2.1、GZIPOutputStream

             主要是通過該類進行壓縮,它由java.util.zip包提供

        2.2、ServletResponse、HttpServletResponse、ServletResponseWrapper、HttpServletResponseWrapper、WrappedOutputStream

              需要繼承HttpServletResponseWrapper,複寫其中的getWriter,getOutputStream方法從而獲得響應資料,然後就可以呼叫gzipOutputStream進行壓縮。

              這裡順道說一下這幾個類的關係

               ServletResponse為最基本的介面,表示response。

               HttpServletResponse擴充套件了ServletRespones,表示http協議下的response

               ServletResponseWrapper實現了ServletResponse

               HttpServletResponseWrapper實現了HttpServletResponse

               所以我們平時用的HttpServletResponse預設的實現為HttpServletResponseWrapper,struts2似乎在這之上又包裝了一層。

               WrappedOutputStream:在我們呼叫getOutputStream方法時,會通過該介面的write方法輸出byte

        2.3思路

              思路很清晰了,通過繼承HttpServletResponseWrapper重寫getWriter,getOutputStream獲得響應資料,在stream的輸出時,需要通過WrappedOutputStream的write方法輸出byte。最後把輸出的byte通過gzipOutputStream進行壓縮

              來看一個實現程式碼

package com.zs.vehicle.filter;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.zip.GZIPOutputStream;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.zs.vehicle.utils.Wrapper;

public class GZipFilter implements Filter{

	@Override
	public void destroy() {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void doFilter(ServletRequest request, ServletResponse response,
			FilterChain chain) throws IOException, ServletException {
		// TODO Auto-generated method stub
		HttpServletResponse resp=(HttpServletResponse) response;
		HttpServletRequest req=(HttpServletRequest) request;
		if(isGZipEncoding(req)){
			Wrapper wrapper=new Wrapper(resp);
			chain.doFilter(request, wrapper);
			byte[] gzipData=gzip(wrapper.getResponseData());
			resp.addHeader("Content-Encoding", "gzip");
			resp.setContentLength(gzipData.length);
			ServletOutputStream output=response.getOutputStream();
			output.write(gzipData);
			output.flush();
		}else{
			chain.doFilter(request, response);
		}
	}

	@Override
	public void init(FilterConfig arg0) throws ServletException {
		// TODO Auto-generated method stub
	}

	private static boolean isGZipEncoding(HttpServletRequest request){
		boolean flag=false;
		String encoding=request.getHeader("Accept-Encoding");
		if(encoding.indexOf("gzip")!=-1){
			flag=true;
		}
		return flag;
	}
	
	private byte[] gzip(byte[] data){
		ByteArrayOutputStream byteOutput=new ByteArrayOutputStream(10240);
		GZIPOutputStream output=null;
		try{
			output=new GZIPOutputStream(byteOutput);
			output.write(data);
		}catch(Exception e){
			e.printStackTrace();
		}finally{
			try{
				output.close();
			}catch(Exception e){
				e.printStackTrace();
			}
		}
		return byteOutput.toByteArray();
	}
	
}

package com.zs.vehicle.utils;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;

import javax.servlet.ServletOutputStream;
import javax.servlet.WriteListener;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;

public class Wrapper extends HttpServletResponseWrapper{
	
	public static final int OT_NONE=0;
	public static final int OT_WRITER=1;
	public static final int OT_STREAM=2;
	private int outputType=OT_NONE;
	private ServletOutputStream output=null;
	private PrintWriter writer=null;
	private ByteArrayOutputStream buffer=null;

	public Wrapper(HttpServletResponse response) {
		super(response);
		buffer=new ByteArrayOutputStream();
	}

	@Override
	public PrintWriter getWriter() throws IOException{
		if(outputType==OT_STREAM)
			throw new IllegalStateException();
		else if(outputType==OT_WRITER)
			return writer;
		else{
			outputType=OT_WRITER;
			writer=new PrintWriter(new OutputStreamWriter(buffer,getCharacterEncoding()));
			return writer;
		}
	}
	
	@Override
	public ServletOutputStream getOutputStream() throws IOException{
		if(outputType==OT_WRITER)
			throw new IllegalStateException();
		else if(outputType==OT_STREAM)
			return output;
		else{
			outputType=OT_STREAM;
			output=new WrappedOutputStream(buffer);
			return output;
		}
	}
	
	@Override
	public void flushBuffer() throws IOException{
		if(outputType==OT_WRITER)
			writer.flush();
		if(outputType==OT_STREAM)
			output.flush();
	}
	
	@Override
	public void reset(){
		outputType=OT_NONE;
		buffer.reset();
	}
	
	public byte[] getResponseData() throws IOException{
		flushBuffer();
		return buffer.toByteArray();
	}
	
	class WrappedOutputStream extends ServletOutputStream{

		private ByteArrayOutputStream buffer;
		
		public WrappedOutputStream(ByteArrayOutputStream buffer){
			this.buffer=buffer;
		}
		
		@Override
		public void write(int b) throws IOException {
			buffer.write(b);
		}
		
		public byte[] toByteArray(){
			return buffer.toByteArray();
		}

		@Override
		public boolean isReady() {
			// TODO Auto-generated method stub
			return true;
		}

		@Override
		public void setWriteListener(WriteListener listener) {
			// TODO Auto-generated method stub
			
		}
		
	}
	
}

      3、spring-boot

              對於spring-boot來說,由於其內嵌了web容器,那麼它的行為是怎樣的呢。

              spring-boot的web容器是預設開啟了gzip壓縮的,而且不會對圖片進行壓縮。