⏰ 2024. 06. 19 수
✔ 스프링 이론 강의를 듣고 정리하면서 작성했습니다.
Spring AOP - 관점 지향 프로그래밍
관점 지향 프로그래밍은 관점
을 기준으로 묶어 개발하는 방식을 의미한다.
관점
이란 어떤 기능을 구현할 때 그 기능을 핵심 기능
과 부가 가능
으로 구분해 각각 하나의 관점으로 보는 것을 의미한다.
핵심 기능
: 각 API 별 수행해야 할 비즈니스 로직이다.
부가 기능
: 핵심기능을 보조하는 부가적인 기능이다.
AOP는 어떤 로직을 기준으로 핵심 기능, 부가 기능으로 나눠서 그 기능을 기준으로 각각 모듈화
하하는 것을 의미한다.
모듈화
란 어떤 공통된 로직이나 기능을 하나의 단위로 묶어 분리하는 것을 의미한다.
모든 핵심 기능
의 Controller에 부가 기능
코드를 추가했을 때, 핵심기능이 100개에 같은 부가기능을 추가해야 한다면 100개의 같은 기능을 추가해야합니다.
같은 함수 내에 핵심 기능과 부가 기능이 같이 있다면, 핵심 기능의 수정이 발생한다면 부가 기능까지 연관되어 수정해야한다.
또, 부가 기능의 수정이 필요하면 핵심 기능도 수정을 해야한다.
이러한 이유들로 부가 기능을 AOP를 통해 모듈화할 필요가 있다.
부가 기능
은 핵심 기능과는 관점이 다르기 때문에 핵심 기능
과 분리해서 부과 기능
을 중심으소 AOP를 설계 구현 가능하다.클래스에 @Aspect
애너테이션을 달아 AOP로 설정한다.
@Aspect
애너테이션은 Bean으로 등록된 클래스에만 적용 가능하다.
어드바이스 해당 AOP 부가 기능의 수행 시점
을 결정한다.
어드바이스 애너테이션 종류
@Around
: '핵심기능' 수행 전과 후 (@Before + @After)@Before
: '핵심기능' 호출 전 (ex. Client 의 입력값 Validation 수행)@After
: '핵심기능' 수행 성공/실패 여부와 상관없이 언제나 동작 (try, catch 의 finally() 처럼 동작)@AfterReturning
: '핵심기능' 호출 성공 시 (함수의 Return 값 사용 가능)@AfterThrowing
: '핵심기능' 호출 실패 시. 즉, 예외 (Exception) 가 발생한 경우만 동작(ex. 예외가 발생했을 때 개발자에게 email 이나 SMS 보냄)포인트컷은 Expression Language의 형태로 작성한고, AOP 부가 기능의 수행 지점
을 결정한다.
포인트컷 Expression 형태
execution(modifiers-pattern? return-type-pattern declaring-type-pattern? method-name-pattern(param-pattern) throws
-pattern?)
?
는 생략 가능
modifiers-pattern : public, private, * 등과 같은 접근 제어자
return-type-pattern : void, String, List, * 등과 같은 반환 값의 타입
declaring-type-pattern : 패키지명 + 클래스명
method-name-pattern(param-pattern) : 함수 명
파라미터 패턴 (param-pattern)
@Pointcut
으로 포인트컷을 선언해 재사용 가능하고 포인트컷 결합(combine)도 가능하다.
EX) @Pointcut
사용 예시
@Component
@Aspect
public class Aspect {
@Pointcut("execution(* com.sparta.myselectshop.controller.*.*(..))")
private void forAllController() {}
@Pointcut("execution(String com.sparta.myselectshop.controller.*.*())")
private void forAllViewController() {}
@Around("forAllContorller() && !forAllViewController()")
public void saveRestApiLog() {
...
}
@Around("forAllContorller()")
public void saveAllApiLog() {
...
}
}
Spring이 프록시(가짜 혹은 대리) 객체를 중간에 삽입한다.
DispatcherServlet
과 ProductController
입장에서는 변화가 전혀 없다.
호출되는 함수의 input
, output
이 완전 동일합니다.
joinPoint.proceed()
에 의해서 원래 호출하려고 했던 함수, 인수(argument) 가 전달된다.
→ createProduct(requestDto);