Filter, Interceptor, AOP는 모두 어떤 작업을 수행하기 전 또는 후에 해야 할 작업을 미리 정의해 둔 것이다. 이 전처리, 후처리의 작업이 각 메서드에서 반복적으로 사용된다면 중복코드가 많이 발생하는데, 그 공통 코드를 분리하고자 하는 목적에서 사용한다. 예를 들어 어떤 작업이 수행하는 데 걸리는 시간을 구한다고 하면, 해당 작업의 수행 전 현재 시간을 저장해 두었다가 수행 후 현재 시간에서 빼면 된다. 이때 수행 전 시간을 구하는 과정, 수행 후 시간을 구하는 과정이 각각 전처리, 후처리 작업이 된다.
1. Filter
- 서블릿 초기화 시 init(), 처리 시 doFilter(), 서블릿 종료 시 destroy()
- Filter는 전처리, 후처리 작업을 모두 doFilter()에서 처리한다.
- ServletContext에 있기 때문에 서블릿에서만 사용 가능하다.
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
// 필터를 적용할 요청의 패턴 지정 - 모든 요청에 필터를 적용.
@WebFilter(urlPatterns="/*")
public class PerformanceFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
// 초기화 작업
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
// 1. 전처리 작업
long startTime = System.currentTimeMillis();
// 2. 서블릿 또는 다음 필터를 호출
chain.doFilter(request, response);
// 3. 후처리 작업
HttpServletRequest req = (HttpServletRequest) request;
String referer = req.getHeader("referer"); // 어디서 요청했는지
String method = req.getMethod();
System.out.println("[" + referer + "] -> " + method + "[" + req.getRequestURI() + "]");
System.out.print("["+((HttpServletRequest)request).getRequestURI()+"]");
System.out.println(" 소요시간="+(System.currentTimeMillis()-startTime)+"ms");
}
@Override
public void destroy() {
// 정리 작업
}
}
2. Interceptor
- 중간에서 가로챈다
- Filter의 발전된 형태
- 전처리, 후처리 시 작업을 각각의 메서드로 분리하였다.
- @Configuration 설정파일에 Interceptor를 등록해야 사용할 수 있다.
- WebApplicationContext(Spring Context)에 있어 Bean에 접근할 수 있다.
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
@Component
public class PerformanceInterceptor implements HandlerInterceptor { // SRP 원칙
// long startTime; // iv, 싱글톤(하나의 객체)이라서 여러 쓰레드가 하나의 객체를 공유
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 1. 전처리 작업
long startTime = System.currentTimeMillis();
request.setAttribute("startTime", startTime);
// handler - 요청과 연결된 컨트롤러의 메서드
HandlerMethod method =(HandlerMethod)handler;
System.out.println("method.getMethod() = " + method.getMethod() + "-- Interceptor 전"); // URL과 연결된 메서드
System.out.println("method.getBean() = " + method.getBean() + "-- Interceptor 전"); // 메서드가 포함된 컨트롤러
// return true이면 다음 인터셉터나 컨트롤러를 호출, false면 호출 안 함
return HandlerInterceptor.super.preHandle(request, response, handler);
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
// 2. 후처리 작업
long endTime = System.currentTimeMillis();
long startTime = (long)request.getAttribute("startTime");
System.out.println(("["+((HttpServletRequest)request).getRequestURI() + "] -- Interceptor 후"));
System.out.println("[소요시간:" + (endTime - startTime) + "ms] -- Interceptor 후");
HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
}
}
@Configuration 붙인 설정 파일에 Interceptor를 등록해야 사용할 수 있다.
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new PerformanceInterceptor())
.addPathPatterns("/**") // 인터셉터를 적용할 대상
.excludePathPatterns("/css/**", "/js/**"); // 인터셉터 적용 제외 대상
}
}
3. AOP
- 중복을 제거하기 위해 공통 코드를 분리한다.
- 실행 중에 코드를 자동 추가한다.
- 부가 기능(Advice)을 동적으로 추가해 주는 기술
- 부가 기능인 Advice를 Target의 pointcut과 연결된 곳에 join 되어 Proxy 객체를 만들고 이 과정은 weaving이라 한다. - before + (핵심 기능) + after // around == before + after
- 로깅, 권한 체크, 트랜잭션, APM
- CGLIB이 클래스 파일의 컴파일되어 있는 곳에 추가한다.
- 서블릿 상관없이 처리할 수 있다.
사용 방법 (w.chatGPT)
- Spring AOP 라이브러리 추가: spring-aspects
- AOP 기능 활성화 @EnableAspectJAutoProxy
- AOP를 적용하는 클래스에 @Aspect 추가 (없으면 @Around 등 인식 못 함)
- AOP 클래스가 Spring 빈으로 등록되어야 함 (@Component, @Bean)
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
import java.util.Arrays;
@Aspect
@Component
public class AroundAdvice {
@Around("execution(* com.fastcampus.ch2.*.*(..))")
public Object methodCallLog(ProceedingJoinPoint pjp) throws Throwable {
long start = System.currentTimeMillis();
System.out.println("<<[start] "
+ pjp.getSignature() + Arrays.deepToString(pjp.getArgs()) + "-- AOP 전");
Object result = pjp.proceed();
System.out.println("result = " + result + "-- AOP 후");
System.out.println("[end]>> " + (System.currentTimeMillis() - start) + "ms -- AOP 후");
return result;
}
}
cf. CGLIB(Code Generator Library) 코드 생성 라이브러리
- 클래스의 바이트 코드를 조작하여 프록시 객체를 생성해 주는 라이브러리
- 소스 레벨이 아닌 클래스 기반을 조작
위 실행 화면은 HomeController.main()을 호출했을 때의 모습이다. 처음에 AOP가 가장 먼저 실행되는 것처럼 보이는데, 자세히 보면 doFilter() 메서드에 적용된 모습이고, 이는 chatGPT에 의하면 AOP가 필터 내부의 메서드를 감쌀 경우 AOP가 먼저 실행될 수 있다고 한다. 아래를 보면 어떤 요청 때 실행되게 할 지 패턴을 적는 곳에 나는 모든 클래스의 모든 메서드로 지정해 놓았기 때문에 실행되었다. 그렇기 때문에 마지막 두 문장도 빼 놓고 생각해야 한다.
@Around("execution(* com.fastcampus.ch2.*.*(..))")
실행 순서는 차례로 Filter, (DispatchServlet), Interceptor, AOP, Controller 순이다. 요청이 들어올 때 이런 순서로 실행된다는 이야기고, 핵심 메서드가 실행을 마친 뒤 후처리하는 순서는 정확히 반대 방향이다.
https://okky.kr/questions/1346808
스프링 Filter와 interceptor가 현업에서 어떻게 쓰이는지 궁금합니다. | OKKY Q&A
안녕하세요,최근에 본 면접을 복기하면서 필터와 인터셉터 (+AOP)의 차이를 묻는 질문이 있었는데요,저는필터는 WAS와 Dispatcher Servlet 사이에서 동작하고, url을 통해 스프링과 상관없는 공통 로직
okky.kr
velog.io/@soyeon207/Spring-Filter-Interceptor-AOP#♀%EF%B8%8F-레퍼런스%EF%BB%BF4
[Spring] Filter, Interceptor, AOP
Filter, Interceptor, AOP 에 대해서 알아보자.
velog.io
'Spring' 카테고리의 다른 글
[Spring] OAuth 2.0 원리 이해 (2) | 2024.10.06 |
---|---|
[Spring] 컴파일 과정, 의존성 추가와 플러그인 설치 차이 (0) | 2024.09.30 |
[Spring] @Lookup - DL(의존관계 조회/탐색) (0) | 2024.08.25 |
[Spring] 객체 지향 프로그래밍의 특징과 좋은 객체 지향 설계의 원칙 5가지, SOLID (0) | 2024.08.17 |
[Spring] Intellij 단축키 모음 (-ing) (0) | 2024.06.26 |