웹 애플리케이션의 성능을 향상시키기 위해 응답시간, 유저 인터렉션 등등 체크가 필요해진다. 이것들을 어떻게 보고 관리해줄 수 있을까?
init()
, doFilter()
, destory()
package com.example.filter;
import jakarta.servlet.*;
import jakarta.servlet.http.HttpServletRequest;
import java.io.IOException;
public class BeerRequestFilter implements Filter {
private FilterConfig fc;
public void init(FilterConfig config) throws ServletException {
this.fc = config;
}
public void doFilter(ServletRequest req, ServletResponse resp,
FilterChain chain) throws ServletException, IOException {
HttpServletRequest httpReq = (HttpServletRequest) req;
String name = httpReq.getRemoteUser();
if(name != null){
fc.getServletContext().log("User " + name + " is updating");
}
chain.doFilter(req, resp); //calling next filter
}
//You must implement destroy method but usually it's empty
public void destroy(){
//clean up
}
}
FilterConfig
object의 refererence 저장한다던가 함.chain.doFilter(req,resp);
가 보이는데 이건 뭘까doFilter()
는 filter의 doFilter()
와는 조금 다르다.destroy()
method를 호출한다.chain.doFilter(req,res)
에 대해 컨테이너에서 어떻게 동작하고 있는지 서술하고 있지 않다. public void doFilter(requeest, response, chain) {
//this is where request handling would go
chain.doFilter(request, response);
//압축 여기서
}
HttpServletResponse
객체를 그냥 implement하게 되면 상당히 많은 메소드를 구현해야 한다.ServletRequestWrapper
HttpServletRequestWrapper
ServletResponseWrapper
HttpServletResponseWrapper
package com.example.filter;
import jakarta.servlet.*;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.zip.GZIPOutputStream;
public class CompressionFilter implements Filter {
private ServletContext ctx;
private FilterConfig cfg;
public void init(FilterConfig cfg) throws ServletException {
this.cfg = cfg;
ctx = cfg.getServletContext();
ctx.log(cfg.getFilterName() + " initialized.");
}
public void doFilter(ServletRequest req,
ServletResponse resp,
FilterChain fc) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) resp;
String valid_encodings = request.getHeader("Accept-Encoding");
if ( valid_encodings.indexOf("gzip")>-1) {
CompressionResponseWrapper wrappedResp = new CompressionResponseWrapper(response);
wrappedResp.setHeader("Content-Encoding", "gzip");
fc.doFilter(request, wrappedResp);
GZIPOutputStream gzos = wrappedResp.getGZIPOutputStream();
gzos.finish();
ctx.log(cfg.getFilterName() + ": finished the request.");
}else {
ctx.log(cfg.getFilterName() + ": no encoding performed.");
fc.doFilter(request, response);
}
}
public void destory(){
cfg = null;
ctx = null;
}
}
package com.example.filter;
import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpServletResponseWrapper;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.util.zip.GZIPOutputStream;
public class CompressionResponseWrapper extends HttpServletResponseWrapper {
private GZIPServletOutputStream servletGZipOs = null;
private PrintWriter pw = null;
private Object streamUsed = null;
public CompressionResponseWrapper(HttpServletResponse response) {
super(response);
}
public void setContentLength(int len) {}
public GZIPOutputStream getGZIPOutputStream() {
return this.servletGZipOs.internalGzipOS;
}
//access to a decorated servlet output stream.
public ServletOutputStream getOutputStream() throws IOException {
if((streamUsed != null) && (streamUsed != pw)) {
throw new IllegalStateException();
}
if(servletGZipOs == null){
servletGZipOs = new GZIPServletOutputStream(getResponse().getOutputStream());
streamUsed = servletGZipOs;
}
return servletGZipOs;
}
public PrintWriter getWriter() throws IOException {
if((streamUsed != null) && (streamUsed != servletGZipOs)){
throw new IllegalStateException();
}
if( pw == null) {
servletGZipOs
= new GZIPServletOutputStream(getResponse().getOutputStream());
OutputStreamWriter outputStreamWriter
= new OutputStreamWriter(servletGZipOs,
getResponse().getCharacterEncoding());
pw = new PrintWriter(outputStreamWriter);
streamUsed = pw;
}
return pw;
}
}
package com.example.filter;
import jakarta.servlet.ServletOutputStream;
import java.io.IOException;
import java.util.zip.GZIPOutputStream;
public class GZIPServletOutputStream extends ServletOutputStream {
GZIPOutputStream internalGzipOS;
//decorator constructor
GZIPServletOutputStream(ServletOutputStream sos) throws IOException {
this.internalGzipOS = new GZIPOutputStream(sos);
}
//write method implements compression decoration.
//this method delegate write() call to the gZIP compression stream.
//기존 ServletOutputStream을 wrapping
//궁극적으로 TCP network output stream을 wrapping한 것.
public void write(int param) throws IOException {
internalGzipOS.write(param);
}
}