지금까지 한 부분은 다음과 같습니다
ServletConfig와 ServletContext 알아보기
전 글을 통해서 알아보실 수 있습니다
오늘 할 부분은 다음과 같습니다
그러면 Servlet 부터 바로 시작해보도록 하겠습니다
Servlet
클라이언트의 응답을 받아 적절한 결과를 돌려주는 프로그래밍 기술정도로만 생각하셔도 좋을 것 같습니다
Servlet 에 대해서 알아보고 싶으시다면
https://mangkyu.tistory.com/14
쪽을 참조해도 좋을 것 같네요
추가로 기억하시면 좋을 부분은, Servlet 에서 꼭 html 만을 반환할 필요는 없다는 점입니다
총 5가지 메서드로 이루어져 있습니다
1. servlet 을 생성한 이후에 호출되는 init 메서드. 초기화 이후에는 config 를 통해 데이터를 받을 수 있다
정확하게 1번만 호출되도록 보장되어 있습니다.
init 이 예외가 터지거나, 시간 초과가 발생하면 servletInfo 를 servlet container 가 등록하지 못합니다
2. getServletConfig() 저장된 servletConfig 를 가져오는 기능
이 서블릿이 초기화 되었을 때, 받았던 객체를 저장해서 반환하도록 만드는 기능입니다
3. service(ServletRequest req,ServletResponse res);
init 이 실행된 이후에 작동한다고 보장되어 있습니다.
서블릿은 멀티쓰레드 환경에서 동작하는 것을 보장해야 합니다.
따라서 공유 리소스에 대한 것을 동기화하는 것에 주의해야 합니다
4. getServletInfo();
작성자, 버전, 저작권 같은 서블릿에 대한 정보가 String 형태로 반환됩니다
5. destroy();
서블릿 컨테이너가 이 서블릿을 사용하지 않는 것을 확정하게 한 경우에, 서블릿이 가지고 있는 자원을 반환할 타이밍을 알려줍니다
public interface Servlet {
public void init(ServletConfig config) throws ServletException;
public ServletConfig getServletConfig();
public void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException;
public String getServletInfo();
public void destroy();
}
GenericServlet
프로토콜에 관계 없이 요청을 처리할 때 사용합니다. http 요청의 경우 httpServlet 이 더 권장됩니다.
최대한 유연하게 작성되어있기에, 대부분의 연산이 빈 연산입니다
빈 연산이나, 큰 의미 없는 연산들은 넘어가고, 기억하면 좋을만한 것들만을 적으려고 합니다
@Override
public void init(ServletConfig config) throws ServletException {
this.config = config;
this.init();
}
public void init() throws ServletException {
// NOOP by default
}
여기서 밑에 메서드를 오버라이딩 하면 this.config=config; 라고 하는 부분을 볼 필요 없이 편하게 사용할 수 있다는 장점이 있습니다
만약 없었다면 super.init()을 호출할 필요가 있었을 것입니다
/**
* Writes the specified message to a servlet log file, prepended by the
* servlet's name. See {@link ServletContext#log(String)}.
*
* @param message
* a <code>String</code> specifying the message to be written to
* the log file
*/
public void log(String message) {
getServletContext().log(getServletName() + ": " + message);
}
/**
* Writes an explanatory message and a stack trace for a given
* <code>Throwable</code> exception to the servlet log file, prepended by
* the servlet's name. See {@link ServletContext#log(String, Throwable)}.
*
* @param message
* a <code>String</code> that describes the error or exception
* @param t
* the <code>java.lang.Throwable</code> error or exception
*/
public void log(String message, Throwable t) {
getServletContext().log(getServletName() + ": " + message, t);
}
메시지 로그를 남기기 좋은 log 형태입니다.
그냥 message 를 남기면 적절한 형태의 message 를 제공할 수 있습니다
예외 상황에서 message, Throwable t를 작성하면 로깅을 깔끔하게 할 수 있다고 합니다
서블릿 context 가 받아서 가지고 있는 것을 보면, servlet container 에서 처리를 해줄 것 같아보입니다
Request와 Response
Servlet 과 항상 함께 하는 인터페이스가 있습니다
ServletRequest, HttpServletRequest
이와 관해서는 정말 잘 정리되어있는 글이 있어서 생략하도록 하겠습니다
ServletRequest 는 http 요청에 대한 것은 아니지만, servlet 에서 왔다 갔다 하는 request, response 이고
HttpServletRequest 는 http 요청에 대한 데이터를 담고 있습니다
ServletRequest 를 상속받습니다
ServletResponse
는 servlet 에서 나오는 reponse 입니다
https://ckddn9496.tistory.com/51
HttpServletResponse
ServletResposne 를 상속받고 있고, http 요청에 대한 응답에 관한 데이터들을 담을 수 있게 되어있습니다
이쪽을 참고하시면 좋을 것 같습니다
HttpServlet
doGet, if the servlet supports HTTP GET requests
doPost, for HTTP POST requests
doPut, for HTTP PUT requests
doDelete, for HTTP DELETE requests
init and destroy, to manage resources that are held for the life of the servlet
getServletInfo, which the servlet uses to provide information about itself
설명을 보시면, doGet, doPost, doPut, doDelete, init, destroy, servletInfo 를 담고 있습니다
다른 메서드를 오버라이딩 하는 것은 대부분 할 필요가 없도록 만들어져있다고 합니다
There's almost no reason to override the service method. service handles standard HTTP requests by dispatching them to the handler methods for each HTTP request type (the doMethod methods listed above).
실제로 다른 메서드들과 다르게
protected void doDelete(HttpServletRequest req,
HttpServletResponse resp)
throws ServletException, IOException {
String msg = lStrings.getString("http.method_delete_not_supported");
sendMethodNotAllowed(req, resp, msg);
}
위와 같은 형태로 기본적으로 작동하지 않는 메서드다 라고 do**** 메서드들은 표현되어 있는 경우가 많습니다
반대로 오버라이딩 할 필요가 없는 것들은
protected void doHead(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
if (DispatcherType.INCLUDE.equals(req.getDispatcherType())) {
doGet(req, resp);
} else {
NoBodyResponse response = new NoBodyResponse(resp);
doGet(req, response);
if (req.isAsyncStarted()) {
req.getAsyncContext().addListener(new NoBodyAsyncContextListener(response));
} else {
response.setContentLength();
}
}
}
이런 느낌으로 잘 만들어져있고요
기본적으로 내부적으로 다양한 메서드들이 이미 정의가 되어있어서, 최소한의 것들만 정의하면 되도록 만들어져있습니다
핵심 로직은
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;
try {
ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
} catch (IllegalArgumentException iae) {
// Invalid date header - proceed as if none was set
ifModifiedSince = -1;
}
if (ifModifiedSince < (lastModified / 1000 * 1000)) {
// 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);
}
}
이 부분인데, 메서드에 따라서 바로 어떤 메서드를 호출하는지 직관적으로 이해할 수 있도록 되어있습니다
'Spring' 카테고리의 다른 글
DispatcherServlet 알아보기 - HttpServletBean편 (0) | 2023.04.26 |
---|---|
Test 의 db 롤백 어디까지 알아보셨나요? (1) | 2023.04.24 |
DispatcherServlet 알아보기 - ServletConfig 편 (0) | 2023.04.19 |
DispatcherServlet 알아보기 - Aware 편 (6) | 2023.04.18 |
모든 객체를 스프링 빈으로 등록해도 괜찮나? (3) | 2023.04.14 |