์šฐ๊ทœ์ด์ธ์šฐ์œค
Eager To Learn ๐ŸŒŒ
์šฐ๊ทœ์ด์ธ์šฐ์œค
์ „์ฒด ๋ฐฉ๋ฌธ์ž
์˜ค๋Š˜
์–ด์ œ

๋ธ”๋กœ๊ทธ ๋ฉ”๋‰ด

  • ๐Ÿก ํ™ˆ
  • ๐Ÿš€ ๊นƒํ—ˆ๋ธŒ
  • โ›… ํƒœ๊ทธ ํด๋ผ์šฐ๋“œ
  • ๋ถ„๋ฅ˜ ์ „์ฒด๋ณด๊ธฐ (217)
    • ๐Ÿ‘จ๐Ÿปโ€๐Ÿ’ป PS (170)
      • JAVA (82)
      • MYSQL (1)
      • Docker (2)
      • PYTHON (24)
      • LeetCode 150 (39)
      • Algorithm ๊ธฐ๋ฒ• (1)
      • ๋ฐ”ํ‚น๋… (21)
    • ๋ธ”๋กœ๊ทธ ์ด์‚ฌ (0)
    • Error (1)
    • CS (15)
      • DataBase (2)
      • OS (7)
      • Network (1)
      • Spring (1)
      • ์ž๋ฃŒ๊ตฌ์กฐ (3)
      • Java (1)
    • Learned (7)
      • Spring (7)
    • ๊ฐœ๋ฐœ์„œ์  (15)
      • ๊ฐ€์ƒ ๋ฉด์ ‘ ์‚ฌ๋ก€๋กœ ๋ฐฐ์šฐ๋Š” ๋Œ€๊ทœ๋ชจ ์‹œ์Šคํ…œ ์„ค๊ณ„ ๊ธฐ์ดˆ (1)
      • ์˜ค๋ธŒ์ ํŠธ - ์กฐ์˜ํ˜ธ (7)
      • ์นœ์ ˆํ•œ SQL ํŠœ๋‹ (7)
    • ํšŒ๊ณ  (2)
hELLO ยท Designed By ์ •์ƒ์šฐ.
์šฐ๊ทœ์ด์ธ์šฐ์œค
Learned/Spring

Dispatcher Servlet์€ ์–ด๋–ป๊ฒŒ ๋™์ž‘ํ• ๊นŒ?

Learned/Spring

Dispatcher Servlet์€ ์–ด๋–ป๊ฒŒ ๋™์ž‘ํ• ๊นŒ?

2023. 8. 17. 16:57

DispatcherServlet ์€ Servlet ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•œ, HTTP ํ”„๋กœํ† ์ฝœ๋กœ ๋“ค์–ด์˜ค๋Š” ๋ชจ๋“  ์š”์ฒญ์„ ๋จผ์ € ๋ฐ›์•„ ์ฒ˜๋ฆฌํ•˜๋Š” Front Controller ์ด๋‹ค.

 

Servlet ์ด๋ž€?

Java ์–ธ์–ด๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ, ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๋ณด๋‚ด๋Š” HTTP ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•˜๊ณ  ์‘๋‹ตํ•˜๋Š” ์—ญํ• ์„ ๋‹ด๋‹นํ•˜๋Š” ์ธํ„ฐํŽ˜์ด์Šค ์ด๋‹ค.

 

public interface Servlet {

    void init(ServletConfig config) throws ServletException;

    ServletConfig getServletConfig();

    void service(ServletRequest req, ServletResponse res) throws ServletException, IOException;

    String getServletInfo();

    void destroy();
}

์œ„์™€ ๊ฐ™์€ ๋ฉ”์„œ๋“œ๋“ค์ด ์ •์˜๋˜์–ด ์žˆ๋‹ค.

 

์ค‘์š”ํ•œ ๋ถ€๋ถ„์€ service(ServletRequest req, ServletResponse res) ์ธ๋ฐ, ํด๋ผ์ด์–ธํŠธ์˜ ์š”์ฒญ์„ ๋ฐ›์•„ ์ฒ˜๋ฆฌํ•˜๊ณ  ์‘๋‹ต์„ ์ƒ์„ฑํ•˜๋Š” ํ•ต์‹ฌ ๋ฉ”์„œ๋“œ์ด๋‹ค.

 

DispatcherServlet ์€ ์ด Servlet ์ธํ„ฐํŽ˜์ด์Šค์˜ ๊ตฌํ˜„์ฒด์ด๊ณ , ๊ฒฐ๊ณผ์ ์œผ๋กœ service() ๋ฉ”์„œ๋“œ๋ฅผ ๊ตฌํ˜„ํ•œ ํŠน์ • ๋ฉ”์„œ๋“œ๋ฅผ ์‹คํ–‰์‹œ์ผœ ํด๋ผ์ด์–ธํŠธ์˜ ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

 

 

์œ„์™€ ๊ฐ™์€ ์ƒ์† ๊ตฌ์กฐ๋ฅผ ๊ฐ–๊ณ  ์žˆ๊ณ , DispatcherServlet ์ด ์–ด๋–ป๊ฒŒ ์‚ฌ์šฉ์ž์˜ ์‘๋‹ต์„ ์ฒ˜๋ฆฌํ•˜๋Š”์ง€ ์‚ดํŽด๋ณด์ž.

 

 

HttpServlet | service()

service()๋Š” ํด๋ผ์ด์–ธํŠธ์˜ ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฉ”์„œ๋“œ๋ผ๊ณ  ํ–ˆ๋‹ค.

 

Servlet ํด๋ž˜์Šค๋ฅผ ์ƒ์†ํ•˜๋Š” ํด๋ž˜์Šค ์ค‘, HttpServlet ์ด ํ•ด๋‹น ๋ฉ”์„œ๋“œ๋ฅผ Override ํ–ˆ๋‹ค.

 

	@Override
    public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {

        HttpServletRequest request;
        HttpServletResponse response;

        try {
            request = (HttpServletRequest) req;
            response = (HttpServletResponse) res;
        } catch (ClassCastException e) {
            throw new ServletException(lStrings.getString("http.non_http"));
        }
        service(request, response);
    }

์—ญํ• ์€, ServletRequest ๋ฅผ HttpServletRequest๋กœ ๋ณ€ํ™˜ํ•˜๊ณ  ServletResponse ๋ฅผ HttpServletResponse๋กœ ๋ณ€ํ™˜ํ•œ ๋’ค,

 

service(HttpServletRequest req, HttpServletResponse res) ๋กœ์„œ service() ๋ฉ”์„œ๋“œ๋ฅผ Overload(OverrideโŒ) ํ•œ ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค.

 

์ด Overload ํ•œ ๋ฉ”์„œ๋“œ๋Š” ํ•˜์œ„ ํด๋ž˜์Šค์ธ FrameWorkServlet ํด๋ž˜์Šค์—์„œ ์ฐพ์„ ์ˆ˜ ์žˆ๋‹ค.

 

FrameWorkServlet | service()

	@Override
	protected void service(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		if (HTTP_SERVLET_METHODS.contains(request.getMethod())) {
			super.service(request, response);
		}
		else {
			processRequest(request, response);
		}
	}
    
    //	private static final Set<String> HTTP_SERVLET_METHODS =
	//		Set.of("DELETE", "HEAD", "GET", "OPTIONS", "POST", "PUT", "TRACE");

 

์šฐ๋ฆฌ๊ฐ€ ์‚ฌ์šฉํ•˜๋Š” ๋Œ€๋ถ€๋ถ„์˜ HTTP ์š”์ฒญ์€ GET, POST, PUT, DELETE ์š”์ฒญ์ด๋ฏ€๋กœ

 

์œ„ ๋กœ์ง์— ๋”ฐ๋ผ, super.service(request,response) ๊ฐ€ ํ˜ธ์ถœ๋˜์–ด FrameworkServlet์˜ ์ƒ์œ„ ํด๋ž˜์Šค์˜ service() ๋ฉ”์„œ๋“œ๊ฐ€ ํ˜ธ์ถœ๋  ๊ฒƒ์ด๋‹ค.

 

๋‹ค์‹œ HttpServlet ํด๋ž˜์Šค์— service(HttpServletRequest req, HttpServletResponse res) ๋ฉ”์„œ๋“œ๊ฐ€ Overload ๋˜์–ด ๊ตฌํ˜„๋˜์–ด์žˆ์œผ๋ฏ€๋กœ ๋Œ์•„์™”๋‹ค. 

 

HttpServlet | service()

    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) {
                doGet(req, resp);
            } else {
                long ifModifiedSince;
                try {
                    ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
                } catch (IllegalArgumentException iae) {
                    ifModifiedSince = -1;
                }
                if (ifModifiedSince < (lastModified / 1000 * 1000)) {
                    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 {
            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);
        }
    }

 

์œ„์™€ ๊ฐ™์€ ๋ฉ”์„œ๋“œ๋กœ ๊ตฌํ˜„๋˜์–ด ์žˆ๋‹ค.

 

๊ฐ HTTP ๋ฉ”์„œ๋“œ์— ๋งž๊ฒŒ doXX ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๊ฒŒ๋” ๋กœ์ง์ด ์ง„ํ–‰๋œ๋‹ค.

 

    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String msg = lStrings.getString("http.method_get_not_supported");
        sendMethodNotAllowed(req, resp, msg);
    }

์œ„ ๋ฉ”์„œ๋“œ๋ฅผ ๋ฐœ๊ฒฌํ•  ์ˆ˜ ์žˆ์—ˆ๋Š”๋ฐ, protected ํ‚ค์›Œ๋“œ๋ฅผ ๋ณด๋‹ˆ ํ•˜์œ„ ํด๋ž˜์Šค์—์„œ ์ƒˆ๋กญ๊ฒŒ ์ •์˜ํ•œ ๋ฉ”์„œ๋“œ๊ฐ€ ์žˆ๊ฒ ๊ตฌ๋‚˜ ์ƒ๊ฐ์ด ๋“ค์–ด์„œ ํ•˜์œ„ ํด๋ž˜์Šค๋ฅผ ํƒ์ƒ‰ํ•ด๋ณด์•˜๋‹ค.

 

HttpServlet์„ ์ƒ์†ํ•œ FrameWorkServlet ํด๋ž˜์Šค์—์„œ Override ํ•œ doXX ๋ฉ”์„œ๋“œ๊ฐ€ ์žˆ์Œ์„ ํ™•์ธํ–ˆ๋‹ค.

 

FrameWorkServlet | doGet()

	@Override
	protected final void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		processRequest(request, response);
	}

 

์œ„์™€ ๊ฐ™์€ ๋ฉ”์„œ๋“œ๋กœ ์ •์˜๋˜์–ด ์žˆ๋Š”๋ฐ, processRequest(request, response) ๋ผ๋Š” ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๊ฒŒ๋” ๋˜์–ด์žˆ๋‹ค.

 

FrameWorkServlet | processRequest()

protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		long startTime = System.currentTimeMillis();
		Throwable failureCause = null;

		LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
		LocaleContext localeContext = buildLocaleContext(request);

		RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
		ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);

		WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
		asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());

		initContextHolders(request, localeContext, requestAttributes);

		try {
			doService(request, response);
		}
		catch (ServletException | IOException ex) {
			failureCause = ex;
			throw ex;
		}
		catch (Throwable ex) {
			failureCause = ex;
			throw new ServletException("Request processing failed: " + ex, ex);
		}

		finally {
			resetContextHolders(request, previousLocaleContext, previousAttributes);
			if (requestAttributes != null) {
				requestAttributes.requestCompleted();
			}
			logResult(request, response, failureCause, asyncManager);
			publishRequestHandledEvent(request, response, startTime, failureCause);
		}
	}

 

์ด๋Ÿฌํ•œ ๋ฉ”์„œ๋“œ๊ฐ€ ์žˆ์—ˆ๋‹ค.

 

๊ฒฐ๋ก ์€ doService(request, response) ๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค.

 

	protected abstract void doService(HttpServletRequest request, HttpServletResponse response)
			throws Exception;

๊ทผ๋ฐ, doService() ๋ฉ”์„œ๋“œ๋Š” ์ถ”์ƒ ๋ฉ”์„œ๋“œ์˜€๋‹ค.

 

์ฆ‰, ์ถ”์ƒ ๋ฉ”์„œ๋“œ๋กœ ์—ญํ• ์„ ์ •์˜ํ•ด๋†“๊ณ  ํ•˜์œ„ ํด๋ž˜์Šค์—์„œ ๊ตฌํ˜„ํ•œ ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๊ฒŒ๋” ํ•˜๋Š” ํ…œํ”Œ๋ฆฟ ๋ฉ”์„œ๋“œ ํŒจํ„ด์ด ์ ์šฉ๋˜์–ด ์žˆ์—ˆ๋‹ค.

 

๊ฒฐ๊ณผ์ ์œผ๋กœ ํ•˜์œ„ ํด๋ž˜์Šค์ธ DispatcherServlet ์—์„œ ๊ตฌํ˜„ํ•œ doService(HttpServletRequest request, HttpServletResponse response) ๊ฐ€ ํ˜ธ์ถœ๋œ๋‹ค.

 

 

DispatcherServlet | doService()

	@Override
	protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
		
        .
        .
        .

		try {
			doDispatch(request, response);
		}
		finally {
			if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
				// Restore the original attribute snapshot, in case of an include.
				if (attributesSnapshot != null) {
					restoreAttributesAfterInclude(request, attributesSnapshot);
				}
			}
			if (this.parseRequestPath) {
				ServletRequestPathUtils.setParsedRequestPath(previousRequestPath, request);
			}
		}
	}

 

DispatcherServlet ์˜ doService() ๋ฉ”์„œ๋“œ๋Š” ๋‹ค์‹œ, doDispatch() ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค.

 

 

DispatcherServlet | doDispatch()

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
		HttpServletRequest processedRequest = request;
		HandlerExecutionChain mappedHandler = null;
		boolean multipartRequestParsed = false;

		WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

		try {
			ModelAndView mv = null;
			Exception dispatchException = null;

			try {
				processedRequest = checkMultipart(request);
				multipartRequestParsed = (processedRequest != request);

				// Determine handler for the current request.
				mappedHandler = getHandler(processedRequest);
				if (mappedHandler == null) {
					noHandlerFound(processedRequest, response);
					return;
				}

				// Determine handler adapter for the current request.
				HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

				// Process last-modified header, if supported by the handler.
				String method = request.getMethod();
				boolean isGet = HttpMethod.GET.matches(method);
				if (isGet || HttpMethod.HEAD.matches(method)) {
					long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
					if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
						return;
					}
				}

				if (!mappedHandler.applyPreHandle(processedRequest, response)) {
					return;
				}

				// Actually invoke the handler.
				mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

				if (asyncManager.isConcurrentHandlingStarted()) {
					return;
				}

				applyDefaultViewName(processedRequest, mv);
				mappedHandler.applyPostHandle(processedRequest, response, mv);
			}
			catch (Exception ex) {
				dispatchException = ex;
			}
			catch (Throwable err) {
				// As of 4.3, we're processing Errors thrown from handler methods as well,
				// making them available for @ExceptionHandler methods and other scenarios.
				dispatchException = new ServletException("Handler dispatch failed: " + err, err);
			}
			processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
		}
		catch (Exception ex) {
			triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
		}
		catch (Throwable err) {
			triggerAfterCompletion(processedRequest, response, mappedHandler,
					new ServletException("Handler processing failed: " + err, err));
		}
		finally {
			if (asyncManager.isConcurrentHandlingStarted()) {
				// Instead of postHandle and afterCompletion
				if (mappedHandler != null) {
					mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
				}
			}
			else {
				// Clean up any resources used by a multipart request.
				if (multipartRequestParsed) {
					cleanupMultipart(processedRequest);
				}
			}
		}
	}

doDispatch() ๋ฉ”์„œ๋“œ๋Š” ์œ„์™€ ๊ฐ™๋‹ค.

 

mappedHandler = getHandler(processedRequest) ๋ถ€๋ถ„์—์„œ ์š”์ฒญ url์„ ๊ธฐ๋ฐ˜์œผ๋กœ ์ ์ ˆํ•œ ํ•ธ๋“ค๋Ÿฌ(Controller)๋ฅผ ์ฐพ๋Š”๋‹ค.

 

๊ทธ๋ฆฌ๊ณ  HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()) ๋ถ€๋ถ„์—์„œ ์ฐพ์€ ํ•ธ๋“ค๋Ÿฌ๋ฅผ ์‹คํ–‰ํ•˜๊ธฐ ์œ„ํ•œ ํ•ธ๋“ค๋Ÿฌ Adapter๋ฅผ ์ฐพ๋Š”๋‹ค.

 

mv = ha.handle(processedRequest, response, mappedHandler.getHandler()) ๋ถ€๋ถ„์—์„œ ํ•ธ๋“ค๋Ÿฌ ์–ด๋ށํ„ฐ๋ฅผ ์‹คํ–‰ํ•˜์—ฌ ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š” Controller ๋กœ์ง์„ ์‹คํ–‰ํ•˜๊ฒŒ ๋œ๋‹ค.

 


์ฐธ๊ณ ํ•œ ๋ธ”๋กœ๊ทธ : https://zzang9ha.tistory.com/441
  • Servlet ์ด๋ž€?
  • HttpServlet | service()
  • FrameWorkServlet | service()
  • HttpServlet | service()
  • FrameWorkServlet | doGet()
  • FrameWorkServlet | processRequest()
  • DispatcherServlet | doService()
  • DispatcherServlet | doDispatch()
'Learned/Spring' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€
  • Spring Boot ์™ธ๋ถ€ API ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ์งœ๋ณด์ž! [MockWebServer vs WireMock]
  • Spring Boot Github ์†Œ์…œ ๋กœ๊ทธ์ธ ๊ตฌํ˜„ํ•˜๊ธฐ [ RestTemplate ยท WebClient ยท FeignClient ๋ฅผ ๋น„๊ตํ•ด๋ณด์ž ]
  • Swagger API ์ ์šฉ ์‹œ, Controller ์ฝ”๋“œ๊ฐ€ ๋„ˆ๋ฌด ๋”๋Ÿฌ์›Œ์ง„๋‹ค.. ๋ถ„๋ฆฌํ•ด๋ณด์ž
  • Dto Validation ์˜ˆ์™ธ ์ฒ˜๋ฆฌ์— AOP๋ฅผ ์ ์šฉํ•ด๋ณด์ž!
์šฐ๊ทœ์ด์ธ์šฐ์œค
์šฐ๊ทœ์ด์ธ์šฐ์œค
๊ฐœ๋ฐœ์ž ๊ฟˆ๋‚˜๋ฌด

ํ‹ฐ์Šคํ† ๋ฆฌํˆด๋ฐ”

๋‹จ์ถ•ํ‚ค

๋‚ด ๋ธ”๋กœ๊ทธ

๋‚ด ๋ธ”๋กœ๊ทธ - ๊ด€๋ฆฌ์ž ํ™ˆ ์ „ํ™˜
Q
Q
์ƒˆ ๊ธ€ ์“ฐ๊ธฐ
W
W

๋ธ”๋กœ๊ทธ ๊ฒŒ์‹œ๊ธ€

๊ธ€ ์ˆ˜์ • (๊ถŒํ•œ ์žˆ๋Š” ๊ฒฝ์šฐ)
E
E
๋Œ“๊ธ€ ์˜์—ญ์œผ๋กœ ์ด๋™
C
C

๋ชจ๋“  ์˜์—ญ

์ด ํŽ˜์ด์ง€์˜ URL ๋ณต์‚ฌ
S
S
๋งจ ์œ„๋กœ ์ด๋™
T
T
ํ‹ฐ์Šคํ† ๋ฆฌ ํ™ˆ ์ด๋™
H
H
๋‹จ์ถ•ํ‚ค ์•ˆ๋‚ด
Shift + /
โ‡ง + /

* ๋‹จ์ถ•ํ‚ค๋Š” ํ•œ๊ธ€/์˜๋ฌธ ๋Œ€์†Œ๋ฌธ์ž๋กœ ์ด์šฉ ๊ฐ€๋Šฅํ•˜๋ฉฐ, ํ‹ฐ์Šคํ† ๋ฆฌ ๊ธฐ๋ณธ ๋„๋ฉ”์ธ์—์„œ๋งŒ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค.