서블릿 컨테이너가
HttpServletResponse
와HttpServletRequest
를 생성 후service()
를 하는 이유에 대해 왜 이미 http 헤더를 분석하여 원하는 서블릿이 무엇인지 아는 시점에서doGet()
,doPost()
를 바로 하지 않고service()
를 호출했는지에 대해 궁금함이 생겨 조사해보았다.
public abstract class HttpServlet extends GenericServlet {
...
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
String method = req.getMethod();
if (method.equals(METHOD_GET)) {
long lastModified = getLastModified(req);
if (lastModified == -1) {
// servlet doesn't support if-modified-since, no reason
// to go through further expensive logic
doGet(req, resp);
} else {
long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
if (ifModifiedSince < lastModified) {
// If the servlet mod time is later, call doGet()
// Round down to the nearest second for a proper compare
// A ifModifiedSince of -1 will always be less
maybeSetLastModified(resp, lastModified);
doGet(req, resp);
} else {
resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
}
}
} else if (method.equals(METHOD_HEAD)) {
long lastModified = getLastModified(req);
maybeSetLastModified(resp, lastModified);
doHead(req, resp);
} else if (method.equals(METHOD_POST)) {
doPost(req, resp);
} else if (method.equals(METHOD_PUT)) {
doPut(req, resp);
} else if (method.equals(METHOD_DELETE)) {
doDelete(req, resp);
} else if (method.equals(METHOD_OPTIONS)) {
doOptions(req,resp);
} else if (method.equals(METHOD_TRACE)) {
doTrace(req,resp);
} else {
//
// Note that this means NO servlet supports whatever
// method was requested, anywhere on this server.
//
String errMsg = lStrings.getString("http.method_not_implemented");
Object[] errArgs = new Object[1];
errArgs[0] = method;
errMsg = MessageFormat.format(errMsg, errArgs);
resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);
}
}
...
}
위의 코드는 HttpServlet
추상클래스의 service()
메서드에 대해 가져온 것이다. 보시면 service()
메서드 내부에서 해당하는 메서드에 맞게 조건을 달아놓은 것을 볼 수 있다. 서블릿 컨테이너에서는 서블릿이 어떤 http 메서드인지 알 필요없이 service()
해주면 되기 때문에 코드가 더 간결해지는 것 같다. 처음엔 서블릿 구현체가 아예없는 추상클래스인 줄 알고 service()
내부에 구현되어 있는 것이 없는 줄 알았다. 하지만 구현체가 있는 메서드여서 바로 이해할 수 있었다.
service()
를 오버라이딩하여 사용하는 경우는 어떤 http 메서드 간에 공통적인 것을 처리하는 경우이다.(하지만 이런 경우는 오버라이딩한 서블릿 클래스를 다시 상속받아 사용해야할 것 같다). 일반적으로는 서블릿에서 doGet()
, doPost()
같은 메서드만 오버라이딩하여 로직을 구현하면 된다.