1. AOP (Aspect Oriented Programming)
- OOP의 보완 개념
- 애플리케이션에서의 관심사의 분리(기능 분리), 핵심적인 기능에서 부가적인 기능 분리
- 핵심 로직을 제외한 모든 부가 로직을 proxy로 처리
- proxy : reflection으로 매개변수 분석 가능

예시

1-1. AOP 용어
- AOP Proxy : AOP 기능 구현을 위해 만든 Proxy 객체 → 스프링에서 AOP Proxy는 JDK 동적 Proxy 또는 CGLIB Proxy
- Join Point : Advice가 적용될 수 있는 위치, AOP를 적용할 수 있는 모든 지점. → 스프링 AOP는 Proxy 방식을 사용하므로 Join Point는 항상 메소드 실행 지점으로 제한.
- Advice : 부가 기능, 특정 join point에서 Aspect에 의해 취해지는 조치 → Around, Before, After 같은 Advice가 있음
- Aspect : Advice + Pointcut을 모듈화 한 것. → 하나의 Advice만이 아닌 여러 Advice와 Pointcut이 함께 존재 가능
- PointCut : Join Point 중 Advice(부가 기능)를 어디에 적용할 지 안할 지 위치를 판단하는 필터링 기능 → 스프링 AOP는 메소드 실행 지점을 PointCut으로 필터링 함

실습
Libarary 주입
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-aop' // aop
}
Annotation 생성
package shop.mtcoding.blog.core;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Hello {
}
AOP 생성
package shop.mtcoding.blog.core.error;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
@Component
@Aspect // AOP 등록
public class GlobalValidationHandler {
@Around("@annotation(shop.mtcoding.blog.core.Hello)")
//@Before("@annotation(org.springframework.web.bind.annotation.GetMapping)")
public Object hello(ProceedingJoinPoint jp) throws Throwable {
System.out.println("aop hello1 before 호출됨");
Object proceed = jp.proceed(); // jp.proceed = @Hello 어노테이션이 붙은 함수 호출
System.out.println("aop hello1 after 호출됨");
return proceed;
}
}
발동
@Hello
@GetMapping("/login-form")
public String loginForm() {
System.out.println("login-form 호출됨 ===================");
return "user/login-form";
}
1-2. Spring AOP 특징
- Spring은 Proxy기반 AOP를 지원
- Spring은 Target 객체에 대한 Proxy를 만들어 제공
- Target을 감싸는 Proxy는 Runtime에 생성됨
- Proxy는 Advice를 Target 객체에 적용하면서 생성되는 객체
- Proxy가 호출을 가로챔 (Interceptor)
- Proxy는 Target 객체에 대한 호출을 가로챈 후 Advice의 부가기능 로직을 수행 후 Target의 핵심기능 로직 호출 → 전처리 Advice
- Target의 핵심기능 로직 메소드 호출 후 부가기능(Advice)을 수행하는 경우도 있음 → 후처리 Advice
2. Interceptor
- 요청에 대한 작업 전/후 로 가로채는 것.
- DS이 컨트롤러 호출 전/후 로 끼어들기 때문에 Spring Context(영역) 내부에서 Controller(Handler)에 관한 요청&응답에 대해 처리
- 스프링의 모든 빈 객체에 접근 가능
- Interceptor는 여러개 사용 가능 (로그인 및 권한 체크, 프로그램 실행시간 계산작업, 로그확인 등)

2-1. HandlerIntercrptor 인터페이스 구현 (Interceptor 주요 메소드 3가지)
- preHandle()
- 컨트롤러 실행 전 호출되는 메소드
- Ex) 인증/인가 체크, 로깅, 요청 파라미터 검증 등의 작업 수행
- pregHandle()에서 false 반환 시 컨트롤러 진입x
- postHandle()
- 컨트롤러 실행 후 view rendering전 호출 메소드
- 주로 컨트롤러 실행 결과 가공 및 모델에 추가적인 데이터를 넣는 등의 작업 수행
- ModelAndView 객체를 조작하여 view에 전달할 데이터 수정 가능
- afterCompletion()
- postHandle() 에서 예외가 발생한 경우에도 afterCompletion()이 호출되며, 예외 처리에 대한 로직 추가가능
- 주로 리소스 정리, 로깅 등의 작업 수행
- view rendering 후 호출 메소드
LoginInterceptor 예시
public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
HttpSession session = request.getSession();
User sessionUser = (User) session.getAttribute("sessionUser");
if(sessionUser == null) {
throw new Exception401("인증되지 않았습니다.");
}
return true; // false = controller 진입x
}
}
WebConfig
@Configuration // IoC에 저장됨
public class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoginInterceptor())
.addPathPatterns("/user/**")
.addPathPatterns("/api/**");
// api가 붙은 주소에는 인증 필요 -> controller, mustache 등
}
}
2-2. MVC와 통합
- MVC의 Interceptor Chain을 구성하여 여러개의 Intercerptor 적용 가능
- Interceptor Chain은 설정된 순서대로 실행, 각각의 Interceptor는 다음 Interceptor로 요청을 전달하거나 Controller 호출 중단 가능
2-3. 전역 및 지역 설정
- Interceptor는 전역 설정 및 특정 URL 패턴에 대해 지역적으로 설정 가능
Share article