-
[2024_동계_모각코] 5회차(01/31)[CNU] Mogakco 2024. 2. 18. 23:26
5회차 목표
Interceptor, Servlet Filter
DispatcherServlet
JPA(ORM)
3. Interceptor, Servlet Filter
둘 다 웹 애플리케이션에서 요청과 응답을 가로채고 처리하는 기능을 제공하는데 사용되지만,각각은 서로 다른 기술과 용도를 가지고 있다.
- Interceptor(인터셉터):
우선 Interceptor는 Spring MVC에서 사용되는 기능으로,Controller 에서 요청을 가로채고 처리하는 인터페이스이다. Spring의 `핸들러 인터셉터(HandlerInterceptor)` 인터페이스를 구현하여 생성하며, 일반적으로 전역적으로 또는 특정 URL 패턴에 대해 적용된다.
- 요청 전에 특정 조건을 검사하여 요청을 중단하거나 다른 컨트롤러로 리다이렉트할 수 있다.
- 요청 전/후에 공통적인 로직을 처리할 수 있다. 예를 들어, 로깅, 보안, 권한 확인 등의 관심사를 구현할 수 있다.
@Slf4j public class LogInterceptor implements HandlerInterceptor { public static final StringLOG_ID= "logId"; @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String requestURI = request.getRequestURI(); String uuid = UUID.randomUUID().toString(); request.setAttribute(LOG_ID, uuid); //@RequestMapping: HandlerMethod //정적 리소스: ResourceHttpRequestHandler if (handler instanceof HandlerMethod) { HandlerMethod hm = (HandlerMethod) handler;//호출할 컨트롤러 메서드의 모든 정보가 포함되어 있다. } log.info("REQUEST [{}][{}][{}]", uuid, requestURI, handler); return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { log.info("postHandle [{}]", modelAndView); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { String requestURI = request.getRequestURI(); String logId = (String) request.getAttribute(LOG_ID); log.info("RESPONSE [{}][{}][{}]", logId, requestURI, handler); if (ex != null) { log.error("afterCompletion error!!", ex); } } }@Configuration public class WebConfig implements WebMvcConfigurer { ... @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new LogInterceptor()) .order(1) .addPathPatterns("/**") .excludePathPatterns("/css/**", "/*.ico", "/error"); registry.addInterceptor(new LoginCheckInterceptor()) .order(2) .addPathPatterns("/**") .excludePathPatterns("/", "/members/add", "/login", "/logout", "/css/**", "/*.ico", "/error"); } }Servlet Filter(서블릿 필터):
Servlet Filter는 Java Servlet 스펙에서 제공하는 기능으로,웹 애플리케이션의 모든 요청과 응답에 대해 가로채고 처리하는 클래스이다. `javax.servlet.Filter` 인터페이스를 구현하여 생성하며, 웹 애플리케이션의 web.xml 파일에 등록하여 동작시킨다.요청에 대한 필터링을 수행하거나 보안 검사를 할 수 있다.
Interceptor와 마찬가지로 로깅, 보안 등의 공통 로직을 처리할 수 있다.
@Slf4j public class LoginCheckFilter implements Filter { private static final String[]whitelist= {"/", "/members/add", "/login", "/logout", "/css/*"}; @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest httpRequest = (HttpServletRequest) request; String requestURI = httpRequest.getRequestURI(); HttpServletResponse httpResponse = (HttpServletResponse) response; try { log.info("인증 체크 필터 시작 {}", requestURI); if (isLoginCheckPath(requestURI)) { log.info("인증 체크 로직 실행 {}", requestURI); HttpSession session = httpRequest.getSession(false); if (session == null || session.getAttribute(SessionConst.LOGIN_MEMBER) == null) { log.info("미인증 사용자 요청 {}", requestURI); //로그인으로 redirect httpResponse.sendRedirect("/login?redirectURL=" + requestURI); return; } } chain.doFilter(request, response); } catch (Exception e) { throw e; //예외 로깅 가능 하지만, 톰캣까지 예외를 보내주어야 함 } finally { log.info("인증 체크 필터 종료 {} ", requestURI); } } /** * 화이트 리스트의 경우 인증 체크X */ private boolean isLoginCheckPath(String requestURI) { return !PatternMatchUtils.simpleMatch(whitelist, requestURI); } }@Bean public FilterRegistrationBean loginCheckFilter() { FilterRegistrationBean<Filter> filterRegistrationBean = new FilterRegistrationBean<>(); filterRegistrationBean.setFilter(new LoginCheckFilter()); filterRegistrationBean.setOrder(2); filterRegistrationBean.addUrlPatterns("/*"); return filterRegistrationBean; }Interceptor와 Servlet Filter는 둘 다 공통 관심사를 처리하는 데 사용되지만, 사용 시기와 적용 범위에 차이가 있다.
Interceptor는 주로 Spring MVC에서 사용되며, 컨트롤러 레벨에서 요청 처리를 가로채는 데 사용된다.
Servlet Filter는 Java Servlet 스펙에 의존하므로 Spring 이외의 웹 프레임워크에서도 사용할 수 있으며, 모든 요청과 응답에 대해 가로채는 범용적인 기능을 가지고 있다.
좀더 자세하게 알아보자.
인터셉터를 사용하는 경우는 다음과 같다.
- Spring MVC에서 주로 사용할 경우.
- 컨트롤러 단위에서 요청과 응답을 가로채고 처리하는 경우.
- Spring의 핸들러 인터셉터를 구현하여 쉽게 생성하고 등록하고 싶은 경우.
- 특정 URL 패턴이나 컨트롤러에만 적용하고 싶은 경우.
- Spring 컨텍스트를 활용하여 의존성 주입(DI) 등의 기능도 활용하고 싶은 경우.
필터를 사용하는 경우:
- Java Servlet 스펙에서 제공하는 기능이므로, Spring 이외의 웹 프레임워크에서도 사용 하고 싶은 경우.
- 웹 애플리케이션 전역적으로 모든 요청과 응답을 가로채고 처리하는 데 주로 활용하고 싶은 경우.
- 모든 요청에 적용되기 때문에 URL 패턴에 제한 없이 모든 요청에 영향을 미치고 싶은 경우.
- 필터가 서블릿 기술에 기반하므로 Spring과 무관하게 독립적으로 동작하길 원하는 경우.
- 스프링 시큐리티도 필터다.
4. DispatcherServlet
Spring MVC에서 핵심적인 컨트롤러 역할을 담당하는 클래스이다.
웹 애플리케이션에 들어오는 모든 클라이언트 요청을 중앙 집중적으로 처리하고, 해당 요청을 적절한 컨트롤러에게 전달하여 처리 결과를 반환하는 역할을 수행한다.
주요 역할
- 요청 분배(Dispatching):
- 클라이언트로부터 들어오는 모든 HTTP 요청을 DispatcherServlet이 가로채서 처리.
- 요청의 URL을 기반으로 적절한 핸들러(컨트롤러)에게 요청을 전달다.
- 핸들러 매핑(Handler Mapping):
- DispatcherServlet은 요청을 어떤 핸들러(컨트롤러)가 처리해야 할지를 결정하기 위해 HandlerMapping을 사용.
- HandlerMapping은 요청의 URL 또는 다른 속성을 기준으로 적절한 핸들러를 찾아주는 역할을 함.
- 핸들러 실행(Handler Execution):
- 선택된 컨트롤러에게 요청을 전달하여 실제 비즈니스 로직을 실행.
- 핸들러는 사용자의 요청을 처리하고, 필요한 작업을 수행한 뒤 결과를 다시 반환.
- View Resolver를 통한 뷰 선택:
- 핸들러가 처리한 결과를 보여주기 위해 View Resolver를 사용하여 적절한 뷰를 선택.
- View Resolver는 논리적인 뷰 이름을 실제 뷰로 매핑하여 클라이언트에게 응답을 생성할 수 있도록 도와줌.
- 응답 생성:
- 선택된 뷰를 사용하여 클라이언트에게 응답을 생성.
- 이때, 모델 데이터와 뷰를 조합하여 HTML, JSON, XML 등의 응답을 생성.
정리하자면,
DispatcherServlet은 Spring MVC의 핵심이며, 전체 요청-응답 주기를 관리하여 클라이언트 요청에 적절한 핸들러를 호출하고, 해당 핸들러의 처리 결과를 클라이언트에게 반환한다.
이를 통해 웹 애플리케이션의 요청 처리 로직을 효과적으로 분리하여 구성할 수 있고, MVC 디자인 패턴을 쉽게 적용할 수 있다.
DispatcherServlet은 기본적으로 Spring의 기본 동작 방식을 따라 싱글톤(Singleton)으로 생성되어서 한 번에 하나의 요청만을 처리할 수 있다.
싱글톤으로 생성된 DispatcherServlet은 웹 애플리케이션의 시작 시점에 초기화되고,
요청이 들어올 때마다 새로운 스레드를 생성하지 않는 대신, 한 번 생성된 DispatcherServlet 인스턴스가 모든 요청을 순차적으로 처리한다.
만약 여러 요청을 동시에 처리하고 싶다면,
서블릿 컨테이너의 설정 에 따라 다중 스레드가 처리 가능한 방식으로 설정하거나,
로드 밸런싱을 통해 여러 인스턴스의 DispatcherServlet을 운영하는 등의 방법을 사용할 수 있다.
수많은 @Controller를 구분하고 요청을 적절한 핸들러(컨트롤러)에게 라우팅하기 위해 핸들러 매핑(HandlerMapping)을 사용한다.
핸들러 매핑은 DispatcherServlet이 요청을 받아서 처리하는 과정에서 가장 먼저 실행되며,
요청의 URL이나 다른 속성을 기준으로 적절한 핸들러를 찾아주는 역할을 하는 기법이다.
일반적으로 사용되는 핸들러 매핑)
- RequestMappingHandlerMapping:
- @RequestMapping 어노테이션을 기반으로 핸들러를 매핑하는 가장 일반적인 핸들러 매핑.
- 요청의 URL과 @RequestMapping 어노테이션이 선언된 메서드 또는 클래스에 매핑되는 것을 찾아 매핑한다.
- BeanNameUrlHandlerMapping:
- 빈의 이름과 URL 패턴을 매핑하여 핸들러를 선택하는 핸들러 매핑.
- 빈의 이름과 요청의 URL이 일치하는 빈을 찾아 매핑한다.
- SimpleUrlHandlerMapping:
- XML 설정 등을 통해 URL 패턴과 핸들러를 매핑하는 간단한 핸들러 매핑.
- XML 설정 파일에서 URL 패턴과 핸들러를 직접 매핑하여 사용한다.
기본적으로 Spring은 RequestMappingHandlerMapping을 사용하여 @RequestMapping 어노테이션과 URL을 기반으로 핸들러를 찾아주는 매핑을 수행한다.
@RequestMapping 어노테이션은 메서드 또는 클래스에 적용되며, 요청의 URL과 매핑되는 핸들러를 선택한다.
따라서 @Controller를 사용하여 정의된 컨트롤러들이 요청을 처리하도록 한다.
5. JPA (ORM)
JPA(Java Persistence API)와 같은 ORM(Object-Relational Mapping)을 사용하는 이유)
- 객체 지향 프로그래밍과 관계형 데이터베이스 를 연결
- 객체 지향 프로그래밍에서는 객체들이 상속, 연관 관계 등을 활용하여 모델링되고,
- 반면에 관계형 데이터베이스는 테이블과 테이블 간의 관계를 사용하여 데이터를 저장한다.
- ORM은 이렇게 패러다임이 다른 두 개념을 연결시키기 위해 객체와 테이블을 매핑하고, 객체 지향적인 방식으로 데이터를 조작할 수 있도록 도와준다.
- 반복적인 SQL 노동, JDBC 코드 감소
- JDBC를 직접 사용하여 SQL을 작성하고 데이터베이스와의 상호작용을 처리하는 것은 반복적이고 복잡한 코드가 불가피하다.
- ORM은 개발자가 직접 SQL을 작성하지 않아도 객체를 통해 데이터를 조작할 수 있도록 해서 개발 생산성을 높인다.
- 유지보수 향상
- 데이터 모델이 변경되는 경우, ORM은 매핑 설정을 통해 데이터베이스 스키마를 자동으로 갱신하거나 변경해줄 수 있다.
- 따라서 데이터베이스 스키마 변경에 따른 번거로움을 줄이고 유지보수성을 높일 수 있다.
- 트랜잭션 관리 , 성능 최적화:
- ORM은 트랜잭션 관리를 지원하여 ACID 속성을 보장하고 데이터 무결성을 유지할 수 있다. ACID : 데이터베이스 트랜잭션이 안전하게 수행된다는 것을 보장하기 위한 성질 (atomicity, consistency, isolation, and durability)**
이러한 이유로 ORM을 사용하여 개발하면 데이터베이스와의 상호작용이 간소화되고,
객체 지향 프로그래밍의 장점을 최대한 활용할 수 있으며,
유지보수성과 개발 생산성을 향상시킬 수 있다.
영속성
영속성은 데이터를 오래 지속시키는 기능을 말하고, 주로 데이터베이스에 객체의 상태를 저장하고, 필요에 따라 수정, 조회, 삭제 등의 작업을 가능하게 한다.
영속성을 통해 객체는 애플리케이션의 실행과 무관하게 데이터베이스에 저장되며, 애플리케이션을 종료하더라도 데이터는 보존된다.
ORM(Object-Relational Mapping) 기술을 사용하여 영속성을 구현하면, 객체와 데이터베이스 간의 매핑 관계를 자동으로 처리할 수 있다.
즉, 쿼리와 테이블을 자동으로 생성하고 관리하는 작업을 대신 처리해주기 때문에 개발자는 데이터베이스와 직접 상호작용하는 SQL 코드를 작성하지 않아도 된다.
- 캐시(Cache) 활용캐시를 사용하면 동일한 데이터를 반복적으로 데이터베이스에서 불러올 필요가 없어져서 I/O 비용을 절감할 수 있다.
- 영속성 계층은 자주 사용되는 데이터를 캐시에 저장하여 데이터베이스 접근을 줄인다.
- 지연 로딩(Lazy Loading)
- 영속성을 통해 연관된 객체를 필요할 때 로딩하는 지연 로딩을 사용하면, 실제로 필요한 데이터만 로딩하여 불필요한 데이터베이스 쿼리를 줄일 수 있다.
- 트랜잭션 관리따라서 데이터베이스의 데이터 무결성과 일관성을 유지할 수 있다.
- 영속성은 트랜잭션 관리를 지원하여 ACID 특성을 보장한다.
- 데이터베이스 독립성이로 인해 다양한 데이터베이스를 지원하는 환경에서도 애플리케이션을 실행할 수 있다.
- 영속성 계층을 사용하여 데이터베이스와의 종속성을 줄일 수 있다.
5회차 회고록
이번 주 모각코에서는 웹 애플리케이션의 요청과 응답을 처리하는 Interceptor와 Servlet Filter, 그리고 Spring MVC의 핵심 컴포넌트인 DispatcherServlet에 대해 깊이 있게 배웠다. 또한, JPA와 같은 ORM 기술의 사용 이유와 영속성 관리에 대해서도 학습했다. 이러한 주제들은 웹 애플리케이션 개발에 있어서 매우 중요한 개념들이며, 각각의 기술이 애플리케이션의 구조와 성능에 미치는 영향을 이해하는 데 큰 도움이 된 것 같다. 오늘은 웹 개발에 있어 핵심적인 요소들을 공부했는데, 앞으로 이러한 개념들을 실제 프로젝트에 적용하고 싶다.
'[CNU] Mogakco' 카테고리의 다른 글
[2024_동계_모각코] 6회차(02/14) (3) 2024.02.18 [2024_동계_모각코] 4회차(01/24) (0) 2024.02.18 [2024_동계_모각코] 3회차(01/17) (3) 2024.02.18 [2024_동계_모각코] 2회차(01/12) (3) 2024.02.18 [2024_동계_모각코] 1회차(01/03) (2) 2024.01.03 - Interceptor(인터셉터):