Filter, Interceptor, AOP는 모두 소프트웨어에서 프로그램의 동작을 제어하기 위한 기법이다.
Filter
웹 애플리케이션에서 HTTP 요청과 응답을 처리하기 위한 기법
Servlet 컨테이너에서 요청과 응답에 대한 처리를 가로채어 필터링하는 역할을 한다.
Filter는 일종의 체인 형태로 구성되어 있어 여러 개의 Filter를 연속적으로 실행할 수 있다.
특징으로는,
- 요청과 응답의 전/후 처리
Filter는 클라이언트로부터 요청이 들어오기 전에 또는 응답이 클라이언트로 보내지기 전에 처리를 수행할 수 있습니다.
예를 들어, 인증, 인가, 로깅, 캐싱 등의 공통적인 처리를 필터로 분리하여 중복 코드를 방지하고 요청과 응답을 처리할 수 있다. - 필터 체인
여러 개의 Filter를 연속적으로 실행할 수 있다.
이를 통해 필터 체인을 구성하여 각각의 Filter에서 원하는 처리를 수행할 수 있다.
필터 체인은 필터의 순서에 따라 실행되며, 체인의 처음과 끝에는 웹 애플리케이션의 시작과 끝을 처리하는 Filter가 위치한다. - 요청/응답의 가로채기
클라이언트와 서버 간의 요청과 응답을 가로채어 처리할 수 있다.
예를 들어, 요청 파라미터의 검증, 응답 헤더의 추가, 응답 데이터의 변환 등을 수행할 수 있다. - 다양한 용도로 활용 가능
예를 들어, 보안 필터, 로깅 필터, 캐싱 필터, 인코딩 필터 등 다양한 기능을 제공하는 Filter가 있다.
Filter는 웹 애플리케이션에서 요청과 응답을 처리하고 제어하는 데에 매우 유용한 기법이며,
중복 코드를 줄이고 웹 애플리케이션의 성능, 보안, 안정성 등을 향상시키는 데에 활용된다.
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
@WebFilter("/*") // 필터를 어떤 URL 패턴에 적용할 것인지 설정
public class LoggingFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
// 필터 초기화 시에 실행되는 코드
}
@Override
public void doFilter(ServletRequest request,
ServletResponse response,
FilterChain chain) throws IOException, ServletException {
// 요청 처리 전에 실행되는 코드
System.out.println("LoggingFilter: Before doFilter()");
// 다음 필터 또는 서블릿으로 체인을 진행
chain.doFilter(request, response);
// 응답 처리 후에 실행되는 코드
System.out.println("LoggingFilter: After doFilter()");
}
@Override
public void destroy() {
// 필터 소멸 시에 실행되는 코드
}
}
Interceptor
Spring Framework에서 제공하는 Interceptor(인터셉터)는 Spring MVC와 같은 웹 애플리케이션에서 요청 처리 과정에 개입하여 공통 기능을 수행하는 기능이다.
요청 전, 후, 그리고 응답 후에 특정 작업을 수행하거나 요청을 가로채어 조작하는 등의 기능을 구현할 수 있다.
Interceptor는 Spring의 핵심 개념 중 하나인 AOP(Aspect-Oriented Programming)의 일부로, 횡단 관심사(cross-cutting concerns)를 처리하기 위해 사용된다.
예를 들어, 로그인 인증, 권한 체크, 요청 로깅, 캐싱 등과 같은 공통적인 작업을 Interceptor를 통해 중복 코드를 피하고, 코드의 재사용성과 유지보수성을 높일 수 있다.
Interceptor는 Spring MVC에서 HTTP 요청과 응답을 처리하는 컨트롤러(Controller)에 적용되며, HandlerInterceptor 인터페이스를 구현하여 사용할 수 있다.
Interceptor는 세 가지 메소드를 제공하며, 각각 다음과 같은 시점에서 호출된다.
- preHandle()
요청 처리 전에 호출되는 메소드로, 요청이 컨트롤러에 도달하기 전에 수행되는 작업을 구현할 수 있다.
예를 들어, 로그인 상태 체크 등의 인증/인가 작업을 수행할 수 있다. - postHandle()
요청 처리 후, 뷰(View)가 렌더링되기 전에 호출되는 메소드로, 컨트롤러가 처리한 결과를 가공하거나 추가 작업을 수행할 수 있다. - afterCompletion()
뷰가 렌더링된 후에 호출되는 메소드로, 요청 처리가 완료된 후에 수행되는 작업을 구현할 수 있다.
예를 들어, 로깅, 자원 해제 등의 작업을 수행할 수 있다.
Interceptor는 Spring의 설정 파일에서 등록하여 사용할 수 있으며, 인터셉터간의 순서도 지정할 수 있습니다. 이를 통해 여러 개의 Interceptor를 조합하여 원하는 로직을 구성할 수 있다.
장점으로는,
- 코드 중복 제거
Interceptor를 사용하여 공통 기능을 여러 컨트롤러에 중복으로 구현하는 것을 방지하여 코드의 중복을 제거한다.
예를 들어, 로그인 인증, 권한 체크, 요청 로깅, 캐싱 등과 같은 공통적인 작업을 Interceptor를 통해 한 곳에서 관리할 수 있다.
이는 코드의 유지보수성을 높이고 코드의 길이를 줄여준다. - 모듈성
각각의 Interceptor를 독립적인 모듈로 개발하고 조합하여 필요한 로직을 구성할 수 있다.
이는 애플리케이션의 기능을 모듈별로 분리하여 개발, 테스트, 관리, 확장을 용이하게 할 수 있다.
또한, 필요에 따라 Interceptor를 추가하거나 제거하여 애플리케이션의 동작을 유연하게 조정할 수 있다. - 유연성
Interceptor를 설정 파일에서 등록하여 사용할 수 있으며, Interceptor 간의 순서도 지정할 수 있다.
이를 통해 여러 개의 Interceptor를 조합하여 원하는 로직을 구성할 수 있다.
또한, Interceptor는 특정 URL 패턴에만 적용하거나, 특정 조건을 만족할 때만 동작하도록 제어할 수 있다.
이는 애플리케이션의 동작을 더욱 세밀하게 제어할 수 있는 유연성을 제공한다. - 재사용성
Interceptor는 공통 기능을 담당하므로, 다양한 컨트롤러에서 재사용될 수 있다.
특정 기능을 Interceptor로 구현하면, 해당 기능을 필요로 하는 다양한 컨트롤러에서 동일한 Interceptor를 사용하여 중복 코드를 피하고 재사용성을 높일 수 있다. - AOP의 일부로서의 횡단 관심사 처리
Interceptor는 Spring의 AOP(Aspect-Oriented Programming) 개념의 일부로 사용되며, 횡단 관심사(cross-cutting concerns)를 처리하기 위해 사용된다.
이를 통해 공통 기능을 애플리케이션의 여러 부분에서 일관되게 적용할 수 있고, AOP의 장점인 코드의 모듈성, 재사용성, 유연성을 활용할 수 있다.
// Interceptor 클래스 생성 //
public class LoggingInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
// 요청 전 처리 로직
System.out.println("요청 전에 로그를 남깁니다.");
return true;
}
@Override
public void postHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler,
ModelAndView modelAndView) throws Exception {
// 요청 후 처리 로직
System.out.println("요청 후에 로그를 남깁니다.");
}
@Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response,
Object handler,
Exception ex) throws Exception {
// 요청 완료 후 처리 로직
System.out.println("요청 완료 후에 로그를 남깁니다.");
}
}
// Interceptor를 applicationContext.xml 또는 Spring Boot의 application.properties 등의 등록설정 파일에 등록 //
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**" />
<bean class="com.example.LoggingInterceptor" />
</mvc:interceptor>
</mvc:interceptors>
// 등록한 Interceptor가 적용될 컨트롤러에서의 동작 //
@Controller
public class MyController {
@RequestMapping("/hello")
public String hello() {
// 컨트롤러의 로직
System.out.println("Hello, World!");
return "hello";
}
}
// LoggingInterceptor는 모든 요청에 대해 로그를 남기는 Interceptor로 설정되어 있다.
// 이로써 모든 컨트롤러의 요청 전, 요청 후, 요청 완료 후에
// 해당 Interceptor가 동작하여 로그를 남길 수 있다.
AOP(Aspect Oriented Programming)
소프트웨어 개발에서 관심사의 분리를 통해 모듈성과 재사용성을 향상시키는 프로그래밍 패러다임이다.
AOP는 관점(Aspect)과 관점을 적용하는 대상(Target)을 기반으로 프로그램을 구조화한다.
관점은 애플리케이션에서 특정한 관심사를 나타내며, 보안, 로깅, 트랜잭션 관리 등이 관점의 예시이다.
AOP는 기존의 객체 지향 프로그래밍(OOP)에 보완적으로 사용된다.
주요한 장점으로는,
- 관심사의 분리
AOP를 사용하면 애플리케이션의 핵심 로직과 관심사(로깅, 보안, 트랜잭션 등)를 분리할 수 있다.
이는 코드의 모듈성을 높이고, 관심사 간의 결합을 낮춰 유지보수와 확장성을 향상시킨다. - 코드 중복 감소
AOP를 사용하여 관심사를 재사용할 수 있으므로, 중복되는 코드를 줄일 수 있다.
예를 들어, 여러 곳에서 로깅을 수행해야 한다면 AOP를 사용하여 한 곳에서 로깅을 처리할 수 있다. - 적용 범위의 유연성
AOP는 어플리케이션 전반에 걸쳐 관심사를 적용할 수 있다.
따라서 관심사의 적용 범위를 유연하게 조절할 수 있다. - 런타임에 적용 가능
AOP는 런타임에 관심사를 적용할 수 있다.
이는 애플리케이션의 동작을 변경하지 않으면서도 관심사를 추가, 수정 또는 제거할 수 있다는 장점이 있다. - 횡단 관심사 처리
AOP는 횡단 관심사(Cross-cutting Concerns)를 처리하기에 적합하다.
횡단 관심사는 여러 모듈에서 공통적으로 필요한 로직으로, AOP를 사용하여 한 곳에서 관리하고 적용할 수 있다.
// Aspect 클래스 생성 //
@Aspect
@Component
public class LoggingAspect {
@Before("execution(* com.example.*.*(..))")
public void logBefore(JoinPoint joinPoint) {
// 메서드 실행 전 로깅
System.out.println("메서드 실행 전 로그를 남깁니다.");
}
@AfterReturning(pointcut = "execution(* com.example.*.*(..))",
returning = "result")
public void logAfterReturning(JoinPoint joinPoint, Object result) {
// 메서드 실행 후 성공적으로 반환된 경우 로깅
System.out.println("메서드 실행 후 로그를 남깁니다. 반환값: " + result);
}
@AfterThrowing(pointcut = "execution(* com.example.*.*(..))",
throwing = "exception")
public void logAfterThrowing(JoinPoint joinPoint, Throwable exception) {
// 메서드 실행 중 예외가 발생한 경우 로깅
System.out.println("메서드 실행 중 예외 발생. 예외 메시지: " + exception.getMessage());
}
@Around("execution(* com.example.*.*(..))")
public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
// 메서드 실행 전/후에 로깅 및 실행 제어
System.out.println("메서드 실행 전 로그를 남깁니다.");
Object result = joinPoint.proceed();
System.out.println("메서드 실행 후 로그를 남깁니다. 반환값: " + result);
return result;
}
}
// 적용할 메서드에 어노테이션 추가 //
@Component
public class MyService {
@Loggable // 커스텀 어노테이션
public void myMethod() {
// 메서드 내용
}
}
// 위의 예시 코드에서 LoggingAspect 클래스는
// AOP를 사용하여 com.example 패키지 내의 모든 메서드 실행 전/후에 로깅을 수행하는 역할을 한다.
// Aspect 클래스에는 다양한 어드바이스(advice)가 있으며,
// @Before, @AfterReturning, @AfterThrowing, @Around 등의 어노테이션을 통해 메서드 실행 전, 후, 예외 발생 시, 실행 전/후에 로직을 추가할 수 있다.
// 이를 통해 관심사를 분리하고, 횡단 관심사를 처리할 수 있습니다.'개발일지' 카테고리의 다른 글
| 병렬프로그래밍이란 (0) | 2023.04.06 |
|---|---|
| RDB와 NoSQL (0) | 2023.04.06 |
| 오버로딩과 오버라이딩의 차이점 (0) | 2023.04.05 |
| 알고리즘에서 '시간복잡도'와 '공간복잡도'란 (0) | 2023.04.05 |
| 절차지향 / 객체지향 / 함수형 프로그래밍 (0) | 2023.04.04 |