[CS] Filter / Interceptor / AOP

hyewon jeong·2023년 3월 29일
0

CS

목록 보기
8/22

Filter, Interceptor, AOP 차이

웹 개발을 하다 보면 실제 비즈니스 로직이 호출되기 이전, 이후에 공통적으로 처리해야 할 기능들이 존재하는데
대표적인 예로 Logging, 인증, 인가, 인코딩 변환 등등이 있다.

공통적인 기능의 코드를 모든 모듈 및 페이지에서 작성하게 되면 코드의 중복이 발생하게 되고 MSA 기반에서는 각 모듈마다 다른 코드가 작성되어 관리가 힘들 수 있다.

따라서 공통 기능을 모아서 처리 할 수 있는 방법으로 위 세가지가 사용된다.

하지만 이 세가지는 약간의 차이점이 존재하는데 우선 호출되는 시기가 다르다.

1. Filter

1-1. 정의

간단히 설명 하면 Filter는 Dispatcher Servlet이 실행 되기전에 수행된다.

여기서 Dispatcher Servlet 이란 적합한 컨트롤러를 찾아 위임 해 주는 역할을 함.

❄️ Filter - 일반적으로 스프링과 무관하게 전역적으로 처리해야 하는 작업들을 처리할때 사용.

Filter는 Spring이 실행 되기전 실행되며 톰캣과 같은 웹컨테이너(WAS)에서 처리를 해주게 된다.
Request / Response에 대한 조작이 가능함
(HTTP 프로토콜로 들어오는 모든 요청을 가장 먼저 받아 처리 함)

따라서 아래와 같은 처리에 적합하다.

  • 공통된 보안 및 인증/인가 관련 작업(XSS방어)
  • 이미지/데이터 압축 및 문자열 인코딩 변환 처리
  • Spring과 분리되어야 하는 기능
  • 모든 요청에 대한 로깅

1-2. 예제코드

2. Interceptor

2-1. 정의

❄️ Interceptor = 로그인 체크, 권한체크, 프로그램 실행시간 계산작업 로그확인 등의 작업
Interceptor는 Dispatcher Servlet에 N개 등록 될 수 있다. - DS가 해당 요청을 처리 가능한 Intercepter에게 할당
(Ex. 로그인 체크, 권한체크, 프로그램 실행시간 계산작업, 로그확인 Interceptor)

스프링의 모든 빈 객체에 접근 할 수있다.

따라서 아래와 같은 처리에 적합하다.

  • 세부적인 보안 및 인증/인가 공통 작업( 특정 사용자는 특정 기능을 사용 못하게 막음)
  • API 호출에 대한 로깅
  • Controller로 넘겨주는 정보(데이터)의 가공
    (필터와 다르게 HttpServletRequest나 HttpServletResponse 등과 같은 객체를 제공받으므로 객체 자체를 조작할 수는 없음,
    대신 해당 객체가 내부적으로 갖는 값은 조작할 수 있으므로 컨트롤러로 넘겨주기 위한 정보를 가공 가능
    EX) JWT 토큰 정보를 파싱해서 컨트롤러에게 사용자의 정보를 제공하도록 가공)

2-2. 예제코드

3. AOP

3-1. 정의

📌aop 개념 및 횡단관심사 정의 정리하기 https://willseungh0.tistory.com/61

❄️ Aop = 주로 '로깅', '트랜잭션', '에러 처리'등 비즈니스단의 메서드에서 조금 더 세밀하게 조정하고 싶을 때 사용 , Interceptor나 Filter와는 달리 메소드 전후의 지점에 자유롭게 설정이 가능하다.
Interceptor와 Filter는 주소(URL)로 대상을 구분해서 걸러내야하는 반면,
AOP는 주소, 파라미터, 애노테이션 등 PointCut이 지원하는 다양한 방법으로 대상을 지정할 수 있다.

URL 기반이 아닌 PointCut 단위로 동작한다.
이 때문에 비즈니스 로직의 메서드 실행 전, 후 단위까지 핸들링 할 수 있다.

참고: https://goddaehee.tistory.com/154


🍓 AOP 방식으로 Logging을 구현한 이유
Logging 요구사항이 개인정보를 처리하는 api들에 대한 로그를 생성하는 것이었다.

따라서 모든 api에 대한 로그와 개인정보를 처리하는 로그를 구분할 필요가 있었고,
메소드 혹은 클래스단위의 처리가 필요해 보였으며 추후 모든 로그를 통합할때도 유연하게 확장을 할 수 있을 것이라고 생각하여 AOP를 선택해 구현 했다.

3-2. AOP 사용 방법

3-2-1. ❄️ Gradle 라이브러리 적용하기

dependencies {
	implementation("org.springframework.boot:spring-boot-starter-aop")
    }

3-2-2. ❄️ 최상위 클래스에 @EnableAspectJAutoProxy 설정하기

main이 있는 최상위 클래스에 어노테이션을 등록해 AOP(@Aspect)를 찾을 수 있게 해준다.

@EnableAspectJAutoProxy
@SpringBootApplication
class LoggingApplication

fun main(args: Array<String>) {
    runApplication<LoggingApplication>(*args)
}

3-2-3. ❄️ 공통기능 정의하기

아래 코드는 단순히 로그를 출력해 주는 기능의 코드다.

@Aspect
@Component
class LogAspect {
     val log: Logger = LoggerFactory.getLogger(LogAspect::class.java)
    
      @Before("bean(*Controller)")
      fun beforeLog(joinPoint: JoinPoint) {
      	log.info("이름이 Controller로 끝나는 모든 @Bean 호출 전 실행되는 로그 입니다.")
      }
      
      @After("execution(* com.miot2j.service.*.*(..))
      fun beforeLog(joinPoint: JoinPoint) {
      	log.info("service 패키지내의 모든 메소드 호출 후 실행되는 로그 입니다.")
      }
}

3-2-4. ❄️ PointCut 설정하기

JoinPoint라는 개념을 설명하기 전에 기본적인 AOP의 개념을 설명 하겠다.

  • Aspect : 위에서 설명한 흩어진 관심사를 모듈화 한 것. 주로 부가기능을 모듈화함.
  • Target : Aspect를 적용하는 곳 (클래스, 메서드 .. )
  • Advice : 실질적으로 어떤 일을 해야할 지에 대한 것, 실질적인 부가기능을 담은 구현체
  • JointPoint : Advice가 적용될 위치, 끼어들 수 있는 지점. 메서드 진입 지점, 생성자 호출 시점, 필드에서 값을 꺼내올 때 등 다양한 시점에 적용가능
  • PointCut : JointPoint의 상세한 스펙을 정의한 것. 'A란 메서드의 진입 시점에 호출할 것'과 같이 더욱 구체적으로 Advice가 실행될 지점을 정할 수 있음
    위 코드에서 알 수 있듯이 @Before("bean(*Controller)") 와 같이
    PointCut을 이름이 Controller로 끝나는 모든 @Bean 호출 전 실행 으로 설정 할 수있다.

대표적인 PointCut 어노테이션은 다음과 같다

  • @Before: 대상 타겟의 호출 전
  • @After: 대상 타겟의 호출 후
  • @After-returning: 대상 타겟의 정상적인 호출 후
  • @After-throwing: 대상 타겟이 예외 발생 시, 예외발생 이후
    (@After - xxx 를 사용하면 좀더 세밀한 설정이 가능 해진다.)
  • @Around: 대상 타겟의 호출 전과 후
    또한 포인트 컷 표현식을 사용할 수 있는데 여기선 @Bean, 인터페이스, 패키지 단위도 설정이 가능하다.

https://velog.io/@miot2j/Spring-Filter-Interceptor-AOP-%EC%B0%A8%EC%9D%B4-%EB%B0%8F-AOP%EB%A5%BC-%EC%82%AC%EC%9A%A9%ED%95%98%EC%97%AC-Logging%EC%9D%84-%EA%B5%AC%ED%98%84%ED%95%9C-%EC%9D%B4%EC%9C%A0

4. Filter / Interceptor / AOP 차이

4-1. Interceptor 와 AOP 의 차이는?

일단 Interceptor 와 AOP 둘 다 스프링에서 자체적으로 기술을 제공하며, 공통 관심사 코드를 뽑아내 적용시키기 위해 나왔다. (물론 AOP 는 스프링이 원조는 아니고, 스프링에서 AOP 를 흉내낸 기술을 제공할 뿐이다.)

AOP 는 메서드 동작의 전 후 과정에 부가로직을 입힐 수 있다.
Interceptor 는 핸들러 동작의 전 후 과정에 부가로직을 입힐 수 있다.

4-2. Filter 와 Interceptor 의 차이는?

기술 제공자

Filter: J2EE 표준 스펙을 구현한 기술이다. 톰캣과 같은 웹 컨테이너에 의해 관리된다.
Interceptor: 스프링에서 제공하는 기술이다. 디스패처 서블릿이 컨트롤러를 호출하기 전과 후에 응답을 참조하거나 가공한다.
관리되는 컨테이너가 각각 웹 컨테이너와 스프링 컨테이너이다.

실행 시점

Filter

  • doFilter(): 요청이 디스패처 서블릿에 전달되기 전에 수행된다.
  • doFilter(): 응답이 디스패처 서블릿을 거치고 난 이후에 수행된다.
    Interceptor
  • preHandle(): 요청이 디스패처 서블릿에 전달된 이후에 수행된다.
  • postHandle(): 응답이 디스패처 서블릿을 거치기 전에 수행된다.

5. 기타 개념 공부

5-1. Servlet(서블릿)

서블릿이란 자바를 사용하여 웹을 만들기 위해 필요한 기술입니다. 그런데 좀더 들어가서 설명하면

클라이언트가 어떠한 요청을 하면 그에 대한 결과를 다시 전송해주어야 하는데, 이러한 역할을 하는 자바 프로그램입니다.

예를 들어, 어떠한 사용자가 로그인을 하려고 할 때. 사용자는 아이디와 비밀번호를 입력하고, 로그인 버튼을 누릅니다.

그때 서버는 클라이언트의 아이디와 비밀번호를 확인하고, 다음 페이지를 띄워주어야 하는데, 이러한 역할을 수행하는

것이 바로 서블릿(Servlet)입니다. 그래서 서블릿은 자바로 구현 된 *CGI라고 흔히 말합니다.

5-1-2. Servlet 특징

  • 클라이언트의 요청에 대해 동적으로 작동하는 웹 어플리케이션 컴포넌트

  • html을 사용하여 요청에 응답한다.

  • Java Thread를 이용하여 동작한다.

  • MVC 패턴에서 Controller로 이용된다.

  • HTTP 프로토콜 서비스를 지원하는 javax.servlet.http.HttpServlet 클래스를 상속받는다.

  • UDP보다 처리 속도가 느리다.

  • HTML 변경 시 Servlet을 재컴파일해야 하는 단점이 있다.

일반적으로 웹서버는 정적인 페이지만을 제공합니다. 그렇기 때문에 동적인 페이지를 제공하기 위해서 웹서버는

다른 곳에 도움을 요청하여 동적인 페이지를 작성해야 합니다. 동적인 페이지로는 임의의 이미지만을 보여주는 페이지와 같이

사용자가 요청한 시점에 페이지를 생성해서 전달해 주는 것을 의미합니다. 여기서 웹서버가 동적인 페이지를 제공할 수 있도록

도와주는 어플리케이션이 서블릿이며, 동적인 페이지를 생성하는 어플리케이션이 CGI입니다.

5-1-3. Servlet 동작 방식

1 . 사용자(클라이언트)가 URL을 입력하면 HTTP Request가 Servlet Container로 전송합니다.
2. 요청을 전송받은 Servlet Container는 HttpServletRequest, HttpServletResponse 객체를 생성합니다.
3. web.xml을 기반으로 사용자가 요청한 URL이 어느 서블릿에 대한 요청인지 찾습니다.
4. 해당 서블릿에서 service메소드를 호출한 후 클리아언트의 GET, POST여부에 따라 doGet() 또는 doPost()를 호출합니다.
5. doGet() or doPost() 메소드는 동적 페이지를 생성한 후 HttpServletResponse객체에 응답을 보냅니다.
6. 응답이 끝나면 HttpServletRequest, HttpServletResponse 두 객체를 소멸시킵니다.

5-2. Dispatcher-Servlet(디스패처 서블릿)의 개념

5-2-1. Dispatcher-Servlet(디스패처 서블릿) 이란?

디스패처 서블릿의 dispatch는 "보내다"라는 뜻을 가지고 있습니다. 그리고 이러한 단어를 포함하는 디스패처 서블릿은 HTTP 프로토콜로 들어오는 모든 요청을 가장 먼저 받아 적합한 컨트롤러에 위임해주는 프론트 컨트롤러(Front Controller)라고 정의할 수 있습니다.

이것을 보다 자세히 설명하자면, 클라이언트로부터 어떠한 요청이 오면 Tomcat(톰캣)과 같은 서블릿 컨테이너가 요청을 받게 됩니다. 그리고 이 모든 요청을 프론트 컨트롤러인 디스패처 서블릿이 가장 먼저 받게 됩니다. 그러면 디스패처 서블릿은 공통적인 작업을 먼저 처리한 후에 해당 요청을 처리해야 하는 컨트롤러를 찾아서 작업을 위임합니다.

여기서 Front Controller(프론트 컨트롤러)라는 용어가 사용되는데, Front Controller는 주로 서블릿 컨테이너의 제일 앞에서 서버로 들어오는 클라이언트의 모든 요청을 받아서 처리해주는 컨트롤러로써, MVC 구조에서 함께 사용되는 디자인 패턴입니다.

5-2-2. Dispatcher-Servlet(디스패처 서블릿)의 동작 과정

앞서 설명한대로 디스패처 서블릿은 적합한 컨트롤러와 메소드를 찾아 요청을 위임해야 합니다. Dispatcher Servlet의 처리 과정을 살펴보면 다음과 같습니다.

  1. 클라이언트의 요청을 디스패처 서블릿이 받음
  2. 요청 정보를 통해 요청을 위임할 컨트롤러를 찾음
  3. 요청을 컨트롤러로 위임할 핸들러 어댑터를 찾아서 전달함
  4. 핸들러 어댑터가 컨트롤러로 요청을 위임함
  5. 비지니스 로직을 처리함
  6. 컨트롤러가 반환값을 반환함
  7. 핸들러 어댑터가 반환값을 처리함
  8. 서버의 응답을 클라이언트로 반환함

"디스패처 서블릿을 통해 요청을 처리할 컨트롤러를 찾아서 위임하고, 그 결과를 받아오는구나"

참고
https://mangkyu.tistory.com/14
https://mangkyu.tistory.com/18
https://jake-seo-dev.tistory.com/83

profile
개발자꿈나무

0개의 댓글