스프링 MVC 전체 구조

직접 만든 프레임워크 스프링 MVC 비교

FrontController           ->  DispatcherServlet

handlerMappingMap  ->  HandlerMapping
MyHandlerAdapter     ->  HandlerAdapter
ModelView                  ->  ModelAndView
viewResolver              ->  ViewResolver

MyView                       ->  View

동작 순서

  1. 핸들러 조회: 핸들러 매핑을 통해 요청 URL에 매핑된 핸들러(컨트롤러)를 조회한다.
  2. 핸들러 어댑터 조회: 핸들러를 실행할 수 있는 핸들러 어댑터를 조회한다.
  3. 핸들러 어댑터 실행: 핸들러 어댑터를 실행한다.
  4. 핸들러 실행: 핸들러 어댑터가 실제 핸들러를 실행한다.
  5. ModelAndView 반환: 핸들러 어댑터는 핸들러가 반환하는 정보를 ModelAndView변환해서 반환한다.
  6. viewResolver 호출: 뷰 리졸버를 찾고 실행한다.
    JSP의 경우: InternalResourceViewResolver 가 자동 등록되고, 사용된다.
  7. View 반환: 뷰 리졸버는뷰의 논리 이름을 물리 이름으로 바꾸고, 렌더링 역할을 담당하는 뷰 객체를  반환한다.
    JSP
    의 경우 InternalResourceView(JstlView) 를 반환하는데, 내부에 forward() 로직이 있다.
  8. 뷰 렌더링: 뷰를 통해서 뷰를 렌더링한다.

HandlerMapping(핸들러 매핑)
핸들러 매핑에서 이 컨트롤러를 찾을 수 있어야 한다.
) 스프링 빈의 이름으로 핸들러를 찾을 수 있는 핸들러 매핑이 필요하다.

HandlerAdapter(핸들러 어댑터)
핸들러 매핑을 통해서 찾은 핸들러를 실행할 수 있는 핸들러 어댑터가 필요하다.
) Controller 인터페이스를 실행할 수 있는 핸들러 어댑터를 찾고 실행해야 한다.

 

스프링은 이미 필요한 핸들러 매핑과 핸들러 어댑터를 대부분 구현해두었다. 개발자가 직접 핸들러 매핑과 핸들러 어댑터를 만드는 일은 거의 없다.

 

스프링 부트가 자동 등록하는 핸들러 매핑과 핸들러 어댑터

(실제로는 더 많지만, 중요한 부분 위주로 설명하기 위해 일부 생략)

HandlerMapping

  • 0 = RequestMappingHandlerMapping : 애노테이션 기반의 컨트롤러인 @RequestMapping에서 사용
  • 1 = BeanNameUrlHandlerMapping : 스프링 빈의 이름으로 핸들러를 찾는다.

HandlerAdapter

  • 0 = RequestMappingHandlerAdapter : 애노테이션 기반의 컨트롤러인 @RequestMapping에서 사용

뷰 리졸버 - InternalResourceViewResolver
스프링 부트는 InternalResourceViewResolver 라는 뷰 리졸버를 자동으로 등록하는데, 이때 application.properties 에 등록한 spring.mvc.view.prefix , spring.mvc.view.suffix 설정 정보를 사용해서 등록한다.

스프링 부트가 자동 등록하는 뷰 리졸버
(실제로는 더 많지만, 중요한 부분 위주로 설명하기 위해 일부 생략)

  • 1 = BeanNameViewResolver : 빈 이름으로 뷰를 찾아서 반환한다. (예: 엑셀 파일 생성 기능에 사용)
  • 2 = InternalResourceViewResolver : JSP를 처리할 수 있는 뷰를 반환한다.

뷰 리졸버 동작 방식

 

1. 핸들러 어댑터 호출
핸들러 어댑터를 통해 new-form 이라는 논리 뷰 이름을 획득한다.

2. ViewResolver 호출
    2-1. new-form 이라는 뷰 이름으로 viewResolver를 순서대로 호출한다.
    2-2. BeanNameViewResolver new-form 이라는 이름의 스프링 빈으로 등록된 뷰를 찾아야 하는데 없다.             
    2-3.
InternalResourceViewResolver 가 호출된다.

3. InternalResourceViewResolver
이 뷰 리졸버는 InternalResourceView 를 반환한다.

4. - InternalResourceView
InternalResourceView JSP처럼 포워드 forward() 를 호출해서 처리할 수 있는 경우에 사용한다.

 

5. view.render()

view.render() 가 호출되고 InternalResourceView forward() 를 사용해서 JSP를 실행한다.

 

 참고
> InternalResourceViewResolver 는 만약 JSTL 라이브러리가 있으면 InternalResourceView

상속받은 JstlView 를 반환한다. JstlView JSTL 태그 사용시 약간의 부가 기능이 추가된다.

 

 참고
> 다른 뷰는 실제 뷰를 렌더링하지만, JSP의 경우 forward() 통해서 해당 JSP로 이동(실행)해야 렌더링이

된다. JSP를 제외한 나머지 뷰 템플릿들은 forward() 과정 없이 바로 렌더링 된다.

 

 참고
> Thymeleaf 뷰 템플릿을 사용하면 ThymeleafViewResolver 를 등록해야 한다. 최근에는 라이브러리만

추가하면 스프링 부트가 이런 작업도 모두 자동화해준다.

'Spring > mvc' 카테고리의 다른 글

MVC 프레임워크 만들기  (0) 2022.07.16
서블릿, JSP, MVC 패턴  (0) 2022.07.16
서블릿  (0) 2022.07.16
HTML, HTTP API, CSR, SSR  (0) 2022.07.03
동시요청 - 멀티 스레드  (0) 2022.07.02

프론트 컨트롤러 패턴 소개

FrontController 패턴 특징

  • 프론트 컨트롤러 서블릿 하나로 클라이언트의 요청을 받음
  • 프론트 컨트롤러가 요청에 맞는 컨트롤러를 찾아서 호출
  • 입구를 하나로!
  • 공통 처리 가능
  • 프론트 컨트롤러를 제외한 나머지 컨트롤러는 서블릿을 사용하지 않아도 됨

스프링 웹 MVC와 프론트 컨트롤러
스프링 웹 MVC의 핵심도 바로 FrontController
스프링 웹 MVCDispatcherServletFrontController 패턴으로 구현되어 있음

 

1. 프론트 컨트롤러 도입 - v1

  • 프론트 컨트롤러를 단계적으로 도입해보자.
  • 이번 목표는 기존 코드를 최대한 유지하면서, 프론트 컨트롤러를 도입하는 것이다.
  • 먼저 구조를 맞추어두고 점진적으로 리펙터링 해보자.

2. View 분리 - v2

모든 컨트롤러에서 뷰로 이동하는 부분에 중복이 있고, 깔끔하지 않다.

String viewPath = "/WEB-INF/views/new-form.jsp";
RequestDispatcher dispatcher = request.getRequestDispatcher(viewPath);
dispatcher.forward(request, response);

이 부분을 깔끔하게 분리하기 위해 별도로 뷰를 처리하는 객체(MyView)를 만들자.

3. Model 추가 - v3

서블릿 종속성 제거

컨트롤러 입장에서 HttpServletRequest, HttpServletResponse이 꼭 필요할까?
요청 파라미터 정보는 자바의 Map으로 대신 넘기도록 하면 지금 구조에서는 컨트롤러가 서블릿 기술을 몰라도 동작할 수 있다.
그리고 request 객체를 Model로 사용하는 대신에 별도의 Model 객체를 만들어서 반환하면 된다. 우리가 구현하는 컨트롤러가 서블릿 기술을 전혀 사용하지 않도록 변경해보자.
이렇게 하면 구현 코드도 매우 단순해지고, 테스트 코드 작성이 쉽다.

뷰 이름 중복 제거

컨트롤러에서 지정하는 뷰 이름에 중복이 있는 것을 확인할 수 있다.
컨트롤러는 뷰의 논리 이름을 반환하고, 실제 물리 위치의 이름은 프론트 컨트롤러에서 처리하도록 단순화 하자.
이렇게 해두면 향후 뷰의 폴더 위치가 함께 이동해도 프론트 컨트롤러만 고치면 된다.

  • /WEB-INF/views/new-form.jsp -> new-form
  • /WEB-INF/views/save-result.jsp -> save-result
  • /WEB-INF/views/members.jsp -> members

ModelView

지금까지 컨트롤러에서 서블릿에 종속적인 HttpServletRequest를 사용했다. 그리고 Model request.setAttribute() 를 통해 데이터를 저장하고 뷰에 전달했다.
서블릿의 종속성을 제거하기 위해 Model을 직접 만들고, 추가로 View 이름까지 전달하는 객체를 만들어보자.

(이번 버전에서는 컨트롤러에서 HttpServletRequest를 사용할 수 없다. 따라서 직접 request.setAttribute() 를 호출할 수 도 없다. 따라서 Model이 별도로 필요하다.)

 

뷰 리졸버

MyView view = viewResolver(viewName)

컨트롤러가 반환한 논리 뷰 이름을 실제 물리 뷰 경로로 변경한다. 그리고 실제 물리 경로가 있는 MyView 객체를 반환한다.
논리 뷰 이름: members
물리 뷰 경로: /WEB-INF/views/members.jsp

view.render(mv.getModel(), request, response)

뷰 객체를 통해서 HTML 화면을 렌더링 한다.
뷰 객체의 render() 는 모델 정보도 함께 받는다.
JSP
request.getAttribute() 로 데이터를 조회하기 때문에, 모델의 데이터를 꺼내서 request.setAttribute() 로 담아둔다.
JSP
로 포워드 해서 JSP를 렌더링 한다.

4. 단순하고 실용적인 컨트롤러 - v4

앞서 만든 v3 컨트롤러는 서블릿 종속성을 제거하고 뷰 경로의 중복을 제거하는 등, 잘 설계된 컨트롤러이다. 그런데 실제 컨트톨러 인터페이스를 구현하는 개발자 입장에서 보면, 항상 ModelView 객체를 생성하고 반환해야 하는 부분이 조금은 번거롭다.
좋은 프레임워크는 아키텍처도 중요하지만, 그와 더불어 실제 개발하는 개발자가 단순하고 편리하게 사용할 수 있어야 한다. 소위 실용성이 있어야 한다.

이번에는 v3를 조금 변경해서 실제 구현하는 개발자들이 매우 편리하게 개발할 수 있는 v4 버전을 개발해보자.

FrontControllerServletV4 는 사실 이전 버전과 거의 동일하다.

모델 객체 전달

Map<String, Object> model = new HashMap<>(); //추가
모델 객체를 프론트 컨트롤러에서 생성해서 넘겨준다. 컨트롤러에서 모델 객체에 값을 담으면 여기에 그대로 담겨있게 된다.

 

뷰의 논리 이름을 직접 반환 (ModelView -> String)

  String viewName = controller.process(paramMap, model);
  MyView view = viewResolver(viewName);

컨트롤로가 직접 뷰의 논리 이름을 반환하므로 이 값을 사용해서 실제 물리 뷰를 찾을 수 있다.

5. 유연한 컨트롤러 - v5

만약 어떤 개발자는 ControllerV3 방식으로 개발하고 싶고, 어떤 개발자는 ControllerV4 방식으로

개발하고 싶다면 어떻게 해야할까?

public interface ControllerV3 {
    ModelView process(Map<String, String> paramMap);
}
public interface ControllerV4 {
        String process(Map<String, String> paramMap, Map<String, Object> model);
}

 

어댑터 패턴

지금까지 우리가 개발한 프론트 컨트롤러는 한가지 방식의 컨트롤러 인터페이스만 사용할 수 있다. ControllerV3 , ControllerV4 는 완전히 다른 인터페이스이다. 따라서 호환이 불가능하다. 마치 v3110v이고, v4220v 전기 콘센트 같은 것이다. 이럴 때 사용하는 것이 바로 어댑터이다.
어댑터 패턴을 사용해서 프론트 컨트롤러가 다양한 방식의 컨트롤러를 처리할 수 있도록 변경해보자.

핸들러 어댑터: 중간에 어댑터 역할을 하는 어댑터가 추가되었는데 이름이 핸들러 어댑터이다. 여기서 어댑터 역할을 해주는 덕분에 다양한 종류의 컨트롤러를 호출할 수 있다.
핸들러: 컨트롤러의 이름을 더 넓은 범위인 핸들러로 변경했다. 그 이유는 이제 어댑터가 있기 때문에 꼭 컨트롤러의 개념 뿐만 아니라 어떠한 것이든 해당하는 종류의 어댑터만 있으면 다 처리할 수 있기 때문이다.

컨트롤러(Controller) -> 핸들러(Handler)
이전에는 컨트롤러를 직접 매핑해서 사용했다. 그런데 이제는 어댑터를 사용하기 때문에, 컨트롤러 뿐만 아니라 어댑터가 지원하기만 하면, 어떤 것이라도 URL에 매핑해서 사용할 수 있다. 그래서 이름을 컨트롤러에서 더 넒은 범위의 핸들러로 변경했다.

'Spring > mvc' 카테고리의 다른 글

스프링 MVC - 구조 이해  (0) 2022.07.26
서블릿, JSP, MVC 패턴  (0) 2022.07.16
서블릿  (0) 2022.07.16
HTML, HTTP API, CSR, SSR  (0) 2022.07.03
동시요청 - 멀티 스레드  (0) 2022.07.02

1. 서블릿으로 회원 관리 웹 애플리케이션 만들기

MemberFormServlet 은 단순하게 회원 정보를 입력할 수 있는 HTML Form을 만들어서 응답한다. 자바 코드로 HTML을 제공해야 하므로 쉽지 않은 작업이다

템플릿 엔진으로

지금까지 서블릿과 자바 코드만으로 HTML을 만들어보았다. 서블릿 덕분에 동적으로 원하는 HTML을 마음껏 만들 수 있다. 정적인 HTML 문서라면 화면이 계속 달라지는 회원의 저장 결과라던가, 회원 목록 같은 동적인 HTML을 만드는 일은 불가능 할 것이다.
그런데, 코드에서 보듯이 이것은 매우 복잡하고 비효율 적이다. 자바 코드로 HTML을 만들어 내는 것 보다 차라리 HTML 문서에 동적으로 변경해야 하는 부분만 자바 코드를 넣을 수 있다면 더 편리할 것이다. 이것이 바로 템플릿 엔진이 나온 이유이다. 템플릿 엔진을 사용하면 HTML 문서에서 필요한 곳만 코드를 적용해서 동적으로 변경할 수 있다.

템플릿 엔진에는 JSP, Thymeleaf, Freemarker, Velocity등이 있다. 다음 시간에는 JSP로 동일한 작업을 진행해보자.

 

2. JSP로 회원 관리 웹 애플리케이션 만들기

서블릿과 JSP의 한계

서블릿으로 개발할 때는 뷰(View)화면을 위한 HTML을 만드는 작업이 자바 코드에 섞여서 지저분하고 복잡했다.
JSP
를 사용한 덕분에 뷰를 생성하는 HTML 작업을 깔끔하게 가져가고, 중간중간 동적으로 변경이 필요한 부분에만 자바 코드를 적용했다. 그런데 이렇게 해도 해결되지 않는 몇가지 고민이 남는다.

회원 저장 JSP를 보자. 코드의 상위 절반은 회원을 저장하기 위한 비즈니스 로직이고, 나머지 하위 절반만 결과를 HTML로 보여주기 위한 뷰 영역이다. 회원 목록의 경우에도 마찬가지다. 코드를 잘 보면, JAVA 코드, 데이터를 조회하는 리포지토리 등등 다양한 코드가 모두 JSP에 노출되어 있다. JSP가 너무 많은 역할을 한다. 이렇게 작은 프로젝트도 벌써 머리가 아파오는데, 수백 수천줄이 넘어가는 JSP를 떠올려보면 정말 지옥과 같을 것이다. (유지보수 지옥 썰)

3. MVC 패턴의 등장

비즈니스 로직은 서블릿 처럼 다른곳에서 처리하고, JSP는 목적에 맞게 HTML로 화면(View)을 그리는 일에 집중하도록 하자. 과거 개발자들도 모두 비슷한 고민이 있었고, 그래서 MVC 패턴이 등장했다. 우리도 직접 MVC 패턴을 적용해서 프로젝트를 리팩터링 해보자.

MVC 패턴 - 개요

너무 많은 역할
하나의 서블릿이나 JSP만으로 비즈니스 로직과 뷰 렌더링까지 모두 처리하게 되면, 너무 많은 역할을 하게되고, 결과적으로 유지보수가 어려워진다. 비즈니스 로직을 호출하는 부분에 변경이 발생해도 해당 코드를 손대야 하고, UI를 변경할 일이 있어도 비즈니스 로직이 함께 있는 해당 파일을 수정해야 한다. HTML 코드 하나 수정해야 하는데, 수백줄의 자바 코드가 함께 있다고 상상해보라! 또는 비즈니스 로직을 하나 수정해야 하는데 수백 수천줄의 HTML 코드가 함께 있다고 상상해보라.

 

변경의 라이프 사이클

사실 이게 정말 중요한데, 진짜 문제는 둘 사이에 변경의 라이프 사이클이 다르다는 점이다. 예를 들어서 UI 를 일부 수정하는 일과 비즈니스 로직을 수정하는 일은 각각 다르게 발생할 가능성이 매우 높고 대부분 서로에게 영향을 주지 않는다. 이렇게 변경의 라이프 사이클이 다른 부분을 하나의 코드로 관리하는 것은 유지보수하기 좋지 않다. (물론 UI가 많이 변하면 함께 변경될 가능성도 있다.)

 

기능 특화

특히 JSP 같은 뷰 템플릿은 화면을 렌더링 하는데 최적화 되어 있기 때문에 이 부분의 업무만 담당하는 것이 가장 효과적이다.

 

Model View Controller

MVC 패턴은 지금까지 학습한 것 처럼 하나의 서블릿이나, JSP로 처리하던 것을 컨트롤러(Controller)와 뷰(View)라는 영역으로 서로 역할을 나눈 것을 말한다. 웹 애플리케이션은 보통 이 MVC 패턴을 사용한다.

  • 컨트롤러: HTTP 요청을 받아서 파라미터를 검증하고, 비즈니스 로직을 실행한다. 그리고 뷰에 전달할 결과 데이터를 조회해서 모델에 담는다.
  • 모델뷰에 출력할 데이터를 담아둔다뷰가 필요한 데이터를 모두 모델에 담아서 전달해주는 덕분에 뷰는 비즈니스 로직이나 데이터 접근을 몰라도 되고화면을 렌더링 하는 일에 집중할 수 있다.
  • 모델에 담겨있는 데이터를 사용해서 화면을 그리는 일에 집중한다여기서는 HTML을 생성하는 부분을 말한다.

< 참고>

컨트롤러에 비즈니스 로직을 둘 수도 있지만, 이렇게 되면 컨트롤러가 너무 많은 역할을 담당한다. 그래서 일반적으로 비즈니스 로직은 서비스(Service)라는 계층을 별도로 만들어서 처리한다. 그리고 컨트롤러는 비즈니스 로직이 있는 서비스를 호출하는 역할을 담당한다. 참고로 비즈니스 로직을 변경하면 비즈니스 로직을 호출하는 컨트롤러의 코드도 변경될 수 있다. 앞에서는 이해를 돕기 위해 비즈니스 로직을 호출한다는 표현 보다는, 비즈니스 로직이라 설명했다.

MVC 패턴 한계
MVC 패턴을 적용한 덕분에 컨트롤러의 역할과 뷰를 렌더링 하는 역할을 명확하게 구분할 수 있다.
특히 뷰는 화면을 그리는 역할에 충실한 덕분에코드가 깔끔하고 직관적이다단순하게 모델에서 필요한 데이터를 꺼내고화면을 만들면 된다.
그런데 컨트롤러는 딱 봐도 중복이 많고필요하지 않는 코드들도 많이 보인다.

 

MVC 컨트롤러의 단점

 

1. 포워드 중복

View로 이동하는 코드가 항상 중복 호출되어야 한다. 물론 이 부분을 메서드로 공통화해도 되지만, 해당 메서드도 항상 직접 호출해야 한다.

  RequestDispatcher dispatcher = request.getRequestDispatcher(viewPath);
  dispatcher.forward(request, response);

2. ViewPath에 중복

String viewPath = "/WEB-INF/views/new-form.jsp";
  • prefix: /WEB-INF/views/
  • suffix: .jsp

그리고 만약 jsp가 아닌 thymeleaf 같은 다른 뷰로 변경한다면 전체 코드를 다 변경해야 한다.

3. 사용하지 않는 코드

다음 코드를 사용할 때도 있고, 사용하지 않을 때도 있다. 특히 response는 현재 코드에서 사용되지 않는다.

  HttpServletRequest request, HttpServletResponse response

그리고 이런 HttpServletRequest , HttpServletResponse 를 사용하는 코드는 테스트 케이스를 작성하기도 어렵다.

4. 공통 처리가 어렵다.
기능이 복잡해질 수 록 컨트롤러에서 공통으로 처리해야 하는 부분이 점점 더 많이 증가할 것이다. 단순히 공통 기능을 메서드로 뽑으면 될 것 같지만, 결과적으로 해당 메서드를 항상 호출해야 하고, 실수로 호출하지 않으면 문제가 될 것이다. 그리고 호출하는 것 자체도 중복이다.


5. 정리하면 공통 처리가 어렵다는 문제가 있다
.
이 문제를 해결하려면 컨트롤러 호출 전에 먼저 공통 기능을 처리해야 한다. 소위 수문장 역할을 하는 기능이 필요하다. 프론트 컨트롤러(Front Controller) 패턴을 도입하면 이런 문제를 깔끔하게 해결할 수 있다. (입구를 하나로!)
스프링 MVC의 핵심도 바로 이 프론트 컨트롤러에 있다.

'Spring > mvc' 카테고리의 다른 글

스프링 MVC - 구조 이해  (0) 2022.07.26
MVC 프레임워크 만들기  (0) 2022.07.16
서블릿  (0) 2022.07.16
HTML, HTTP API, CSR, SSR  (0) 2022.07.03
동시요청 - 멀티 스레드  (0) 2022.07.02

스프링부트 서블릿 등록, 사용

@ServletComponentScan

스프링 부트는 서블릿을 직접 등록해서 사용할 수 있도록 @ServletComponentScan 을 지원한다.
다음과 같이 추가하자.

 

@WebServlet

서블릿 애노테이션 name: 서블릿 이름 urlPatterns: URL 매핑

 

hello.servlet.ServletApplication

package hello.servlet;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;

@ServletComponentScan //서블릿 자동 등록 
@SpringBootApplication
public class ServletApplication {
     public static void main(String[] args) {
        SpringApplication.run(ServletApplication.class, args);
	} 
}

hello.servlet.basic.HelloServlet

package hello.servlet.basic;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet(name = "helloServlet", urlPatterns = "/hello")
public class HelloServlet extends HttpServlet {
	@Override
	protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		System.out.println("HelloServlet.service");
        System.out.println("request = " + request);
        System.out.println("response = " + response);
        String username = request.getParameter("username");
        System.out.println("username = " + username);
        response.setContentType("text/plain");
        response.setCharacterEncoding("utf-8");
		response.getWriter().write("hello " + username);
	}
}

서블릿 컨테이너 동작방식

HttpServletRequest

HttpServletRequest 역할

HTTP 요청 메시지를 개발자가 직접 파싱해서 사용해도 되지만, 매우 불편할 것이다.
서블릿은 개발자가 HTTP 요청 메시지를 편리하게 사용할 수 있도록 개발자 대신에 HTTP 요청 메시지를 파싱한다.
그리고 그 결과를 HttpServletRequest 객체에 담아서 제공한다.

HttpServletRequest를 사용하면 다음과 같은 HTTP 요청 메시지를 편리하게 조회할 수 있다.

HTTP 요청 메시지

POST /save HTTP/1.1
Host: localhost:8080
Content-Type: application/x-www-form-urlencoded

username=kim&age=20

HttpServletRequest 개요

START LINE

  • HTTP 메소드
  • URL
  • 쿼리 스트링
  • 스키마, 프로토콜 헤더

헤더

  • 헤더 조회

바디

  • form 파라미터 형식 조회
  • message body 데이터 직접 조회

HttpServletRequest 객체는 추가로 여러가지 부가기능도 함께 제공한다.

 

임시 저장소 기능

  • 해당 HTTP 요청이 시작부터 끝날 때 까지 유지되는 임시 저장소 기능
    - 저장: request.setAttribute(name, value)
    - 조회: request.getAttribute(name)

세션 관리 기능

request.getSession(create: true)

HttpServletResponse

HttpServletResponse 역할

  • HTTP 응답 메시지 생성
  • HTTP 응답코드 지정 헤더 생성
  • 바디 생성

 

편의 기능 제공

  • Content-Type, 쿠키, Redirect

 

'Spring > mvc' 카테고리의 다른 글

MVC 프레임워크 만들기  (0) 2022.07.16
서블릿, JSP, MVC 패턴  (0) 2022.07.16
HTML, HTTP API, CSR, SSR  (0) 2022.07.03
동시요청 - 멀티 스레드  (0) 2022.07.02
서블릿, 서블릿 컨테이너  (0) 2022.06.05

정적 리소스

  • 고정된 HTML 파일, CSS, JS, 이미지, 영상 등을 제공
  • 주로 웹 브라우저

동적 리소스

1. HTML 페이지

  • 동적으로 필요한 HTML 파일을 생성해서 전달
  • 웹 브라우저: HTML 해석

2. HTTP API

  • HTML이 아니라 데이터를 전달
  • 주로 JSON 형식 사용
  • 다양한 시스템에서 호출
  • 데이터만 주고 받음, UI 화면이 필요하면, 클라이언트가 별도 처리
  • 주로 JSON 형태로 데이터 통신
  • UI 클라이언트 접점
  • 앱 클라이언트(아이폰, 안드로이드, PC 앱)
  • 웹 브라우저에서 자바스크립트를 통한 HTTP API 호출
  • React, Vue.js 같은 웹 클라이언트

3. 서버 to 서버

  • 주문 서버 -> 결제 서버
  • 기업간 데이터 통신

서버사이드 렌더링, 클라이언트 사이드 렌더링

SSR - 서버 사이드 렌더링

  • HTML 최종 결과를 서버에서 만들어서 웹 브라우저에 전달 주로 정적인 화면에 사용
  • 관련기술: JSP, 타임리프 -> 백엔드 개발자

CSR - 클라이언트 사이드 렌더링

  • HTML 결과를 자바스크립트를 사용해 웹 브라우저에서 동적으로 생성해서 적용
  • 주로 동적인 화면에 사용, 웹 환경을 마치 앱 처럼 필요한 부분부분 변경할 수 있음
  • 예) 구글 지도, Gmail, 구글 캘린더
  • 관련기술: React, Vue.js -> 웹 프론트엔드 개발자

참고

  • React, Vue.js를 CSR + SSR 동시에 지원하는 웹 프레임워크도 있음
  • SSR을 사용하더라도, 자바스크립트를 사용해서 화면 일부를 동적으로 변경 가능


'Spring > mvc' 카테고리의 다른 글

서블릿, JSP, MVC 패턴  (0) 2022.07.16
서블릿  (0) 2022.07.16
동시요청 - 멀티 스레드  (0) 2022.07.02
서블릿, 서블릿 컨테이너  (0) 2022.06.05
웹 애플리케이션의 이해  (0) 2022.06.05

쓰레드

  • 애플리케이션 코드를 하나하나 순차적으로 실행하는 것은 쓰레드
  • 자바 메인 메서드를 처음 실행하면 main이라는 이름의 쓰레드가 실행
  • 쓰레드가 없다면 자바 애플리케이션 실행이 불가능
  • 쓰레드는 한번에 하나의 코드 라인만 수행
  • 동시 처리가 필요하면 쓰레드를 추가로 생성

단일 요청 - 쓰레드 하나 사용

다중 요청 - 쓰레드 하나 사용

  • 나중에 들어온 요청이 대기하게 된다. 동시 요청 처리 불가

요청 마다 쓰레드 사용

  • 동시 요청을 처리할 수 있다.
  • 장점
    리소스(CPU, 메모리)가 허용할 때 까지 처리가능
    하나의 쓰레드가 지연 되어도, 나머지 쓰레드는 정상 동작한다.
  • 단점
    쓰레드는 생성 비용은 매우 비싸다.
    고객의 요청이 올 때 마다 쓰레드를 생성하면, 응답 속도가 늦어진다.
    쓰레드는 컨텍스트 스위칭 비용이 발생한다.
    쓰레드 생성에 제한이 없다.
    고객 요청이 너무 많이 오면, CPU, 메모리 임계점을 넘어서 서버가 죽을 수 있다.

쓰레드 풀

  • 필요한 쓰레드를 쓰레드 풀에 보관하고 관리한다.
  • 특징
    쓰레드 풀에 생성 가능한 쓰레드의 최대치를 관리한다.
    톰캣은 최대 200개 기본 설정 (변경 가능)
  • 사용
    쓰레드가 필요하면, 이미 생성되어 있는 쓰레드를 쓰레드 풀에서 꺼내서 사용한다.
    사용을 종료하면 쓰레드 풀에 해당 쓰레드를 반납한다.
    최대 쓰레드가 모두 사용중이어서 쓰레드 풀에 쓰레드가 없으면? 기다리는 요청은 거절하거나 특정 숫자만큼만 대기하도록 설정할 수 있다.
  • 장점
    쓰레드가 미리 생성되어 있으므로, 쓰레드를 생성하고 종료하는 비용(CPU)이 절약되고, 응답 시간이 빠르다.
    생성 가능한 쓰레드의 최대치가 있으므로 너무 많은 요청이 들어와도 기존 요청은 안전하게 처리할 수 있다.
  • 실무 팁
    WAS의 주요 튜닝 포인트는 최대 쓰레드(max thread) 수이다.
    이 값을 너무 낮게 설정하면?
    동시 요청이 많으면, 서버 리소스는 여유롭지만, 클라이언트는 금방 응답 지연
    이 값을 너무 높게 설정하면
    ?
    동시 요청이 많으면, CPU, 메모리 리소스 임계점 초과로 서버 다운
    장애 발생시
    ?
    클라우드면 일단 서버부터 늘리고, 이후에 튜닝 클라우드가 아니면 열심히 튜닝
  • 성능 테스트
    최대한 실제 서비스와 유사하게 성능, 테스트 시도 툴: 아파치 ab, 제이미터, nGrinder
  • 멀티 쓰레드에 대한 부분은 WAS가 처리
    개발자가 멀티 쓰레드 관련 코드를 신경쓰지 않아도 됨
    개발자는 마치 싱글 쓰레드 프로그래밍을 하듯이 편리하게 소스 코드를 개발
    멀티 쓰레드 환경이므로 싱글톤 객체(서블릿, 스프링 빈)는 주의해서 사용

 

'Spring > mvc' 카테고리의 다른 글

서블릿, JSP, MVC 패턴  (0) 2022.07.16
서블릿  (0) 2022.07.16
HTML, HTTP API, CSR, SSR  (0) 2022.07.03
서블릿, 서블릿 컨테이너  (0) 2022.06.05
웹 애플리케이션의 이해  (0) 2022.06.05

서블릿

클라이언트의 요청을 처리하고, 그 결과를 반환하는 Servlet 클래스의 구현 규칙을 지킨 자바 웹 프로그래밍 

개발자가 비즈니스 로직에 집중할 수 있도록 소켓 연결등의 잡일을 지원한다

@WebServlet(name = "helloServlet", urlPatterns = "/hello") 
public class HelloServlet extends HttpServlet {
    @Override protected void service(HttpServletRequest request, HttpServletResponse response){ 
    	//애플리케이션 로직 
    }
}
  • urlPatterns(/hello) URL🕔 호출되면 서블릿 코드가 실행
  • HTTP 요청 정보를 편리하게 사용할 있는 HttpServletRequest
  • HTTP 응답 정보를 편리하게 제공할 있는 HttpServletResponse
  • 개발자는 HTTP 스펙을 매우 편리하게 사용

  • HTTP 요청시
  • WAS는 Request, Response 객체를 새로 만들어서 서블릿 객체 호출
  • 개발자는 Request 객체에서 HTTP 요청 정보를 편리하게 꺼내서 사용
  • 개발자는 Response 객체에 HTTP 응답 정보를 편리하게 입력
  • WAS는 Response 객체에 담겨있는 내용으로 HTTP 응답 정보를 생성

서블릿 컨테이너

  • 톰캣처럼 서블릿을 지원하는 WAS를 서블릿 컨테이너라고 함
  • 서블릿 컨테이너는 서블릿 객체를 생성, 초기화, 호출, 종료하는 생명주기 관리
  • 서블릿 객체는 싱글톤으로 관리
    - 고객의 요청이 올 때 마다 계속 객체를 생성하는 것은 비효율
    - 최초 로딩 시점에 서블릿 객체를 미리 만들어두고 재활용
    - 모든 고객 요청은 동일한 서블릿 객체 인스턴스에 접근
    - 공유 변수 사용 주의
    - 서블릿 컨테이너 종료시 함께 종료
  • JSP도 서블릿으로 변환 되어서 사용
  • 동시 요청을 위한 멀티 쓰레드 처리 지원

 

'Spring > mvc' 카테고리의 다른 글

서블릿, JSP, MVC 패턴  (0) 2022.07.16
서블릿  (0) 2022.07.16
HTML, HTTP API, CSR, SSR  (0) 2022.07.03
동시요청 - 멀티 스레드  (0) 2022.07.02
웹 애플리케이션의 이해  (0) 2022.06.05

웹 서버(Web Server)

  • HTTP 기반으로 동작
  • 정적 리소스 제공, 기타 부가기능
  • 정적(파일) HTML, CSS, JS, 이미지, 영상
  • 예) NGINX, APACHE

웹 애플리케이션 서버(WAS - Web Application Server)

  • HTTP 기반으로 동작
  • 웹 서버 기능 포함+ (정적 리소스 제공 가능)
  • 프로그램 코드를 실행해서 애플리케이션 로직 수행
     - 동적 HTML, HTTP API(JSON)
    - 서블릿, JSP, 스프링 MVC
  • ) 톰캣(Tomcat) Jetty, Undertow

웹 서버, 웹 애플리케이션 서버(WAS) 차이

  • 웹 서버는 정적 리소스(파일), WAS는 애플리케이션 로직 사실은 둘의 용어도 경계도 모호함
  • 웹 서버도 프로그램을 실행하는 기능을 포함하기도 함
  • 웹 애플리케이션 서버도 웹 서버의 기능을 제공함
  • 자바는 서블릿 컨테이너 기능을 제공하면 WAS
  • 서블릿 없이 자바코드를 실행하는 서버 프레임워크도 있음 WAS는 애플리케이션 코드를 실행하는데 더 특화

1. 웹 시스템 구성 - WAS, DB

  • WAS, DB 만으로 시스템 구성 가능
  • WAS는 정적 리소스, 애플리케이션 로직 모두 제공 가능

단점

  •  WAS가 너무 많은 역할을 담당, 서버 과부하 우려
  • 가장 비싼 애플리케이션 로직이 정적 리소스 때문에 수행이 어려울 수 있음
  • WAS 장애시 오류 화면도 노출 불가능 

2. 웹 시스템 구성 - WEB, WAS, DB   ( 1 보다 좋다)

  • 정적 리소스는 웹 서버가 처리
  • 웹 서버는 애플리케이션 로직같은 동적인 처리가 필요하면 WAS에 요청을 위임
  • WAS는 중요한 애플리케이션 로직 처리 전담

장점

  • 효율적인 리소스 관리
    - 정적 리소스가 많이 사용되면 Web 서버 증설
    - 애플리케이션 리소스가 많이 사용되면 WAS 증설
  • 정적 리소스만 제공하는 웹 서버는 잘 죽지 않음 but, 애플리케이션 로직이 동작하는 WAS 서버는 잘 죽음
  • WAS, DB 장애시 WEB 서버가 오류 화면 제공 가능

 

'Spring > mvc' 카테고리의 다른 글

서블릿, JSP, MVC 패턴  (0) 2022.07.16
서블릿  (0) 2022.07.16
HTML, HTTP API, CSR, SSR  (0) 2022.07.03
동시요청 - 멀티 스레드  (0) 2022.07.02
서블릿, 서블릿 컨테이너  (0) 2022.06.05

+ Recent posts