Spring AOP란?
AOP는 Aspect Oriented Programming의 약자로 관점 지향 프로그래밍이라고 불린다.
관점 지향은 쉽게 말해 어떤 로직을 기준으로 핵심적인 관점, 부가적인 관점으로 나누어서 보고 그 관점을 기준으로 각각 모듈화하겠다는 것이다.
여기서 모듈화란 어떤 공통된 로직이나 기능을 하나의 단위로 묶는 것을 말한다.
AOP에서 각 관점을 기준으로 로직을 모듈화한다는 것은 코드들을 부분적으로 나누어서 모듈화하겠다는 의미다. 이때, 소스 코드상에서 다른 부분에 계속 반복해서 쓰는 코드들을 발견할 수 있는 데 이것을 흩어진 관심사 (Crosscutting Concerns)라 부른다.
AOP 주요 개념
Aspect
위에서 설명한 흩어진 관심사를 모듈화 한 것. 주로 부가기능을 모듈화함.
Target
Aspect를 적용하는 곳 (클래스, 메서드 .. )
Advice
실질적으로 어떤 일을 해야할 지에 대한 것, 실질적인 부가기능을 담은 구현체
JointPoint
Advice가 적용될 위치, 끼어들 수 있는 지점. 메서드 진입 지점, 생성자 호출 시점, 필드에서 값을 꺼내올 때 등 다양한 시점에 적용가능
PointCut
JointPoint의 상세한 스펙을 정의한 것. 'A란 메서드의 진입 시점에 호출할 것'과 같이 더욱 구체적으로 Advice가 실행될 지점을 정할 수 있음
기본 설정
1. 라이브러리 종속성 추가
dependencies {
compile group: 'org.springframework.boot', name: 'spring-boot-starter-aop'
}
2. @EnableAspectAutoProxy 추가
@EnableAspectAutoProxy
@SpringBootApplication
public class SomeApplication {
public static void main(String[] args) {
ApplicationContext ctx = SpringApplication.run(Application.class, args);
}
}
3. @Aspect 클래스 작성
@Aspect
@Component
@Order(Ordered.LOWEST_PRECEDENCE)
@RequiredArgsConstructor
public class LogAspect {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@Around("execution(* com.beekei.shop.user.ui.*Controller.*(..))")
public Object logging(ProceedingJoinPoint p) throws Throwable {
logger.info("aop logging test!!");
return p.proceed(); // 다음 로직 실행
}
}
- @Aspect - Aspect를 나타내는 클래스라는 것을 명시
- @Component - Spring Bean 등록
- @Order - @Aspect 빈 간의 작동 순서 설정(int type - 낮을수록 우선순위가 높음)
default : Ordered.LOWEST_PRECEDENCE
어드바이스(Advice)
@Before
대상 메서드의 실행 전에 끼어 들어 원하는 작업을 할 수 있다.
끼어들기만 할 뿐 대상 메서드의 제어나 가공은 불가능하다.
@Before("execution(* com.beekei.shop.user.ui.*Controller.*(..))")
public void logging(JoinPoint joinPoint) throws Throwable {
logger.info("aop logging test!!");
return p.proceed();
}
- PointCut - 어드바이스에 작성된 파라메터, 끼어들 메써드의 범위를 지정
- JoinPoint - 오브젝트는 끼어든 메써드의 정보 제공
@After
대상 메서드의 실행 후에 끼어 들어 원하는 작업을 할 수 있다.
끼어들기만 할 뿐 대상 메서드의 제어나 가공은 불가능하다.
@After("execution(* com.beekei.shop.user.ui.*Controller.*(..))")
public void logging(JoinPoint joinPoint) throws Throwable {
logger.info("aop logging test!!");
}
@AfterReturning
해당 메서드의 실행이 종료되어 값을 리턴할 때 끼어 들 수 있다.
리턴 값을 확인할 수 있을 뿐 대상 메서드의 제어나 가공은 불가능하다.
@AfterReturning(pointcut = "execution(* com.beekei.shop.user.ui.*Controller.*(..))", returning = "result")
public void logging(JoinPoint joinPoint, Object result) {
logger.info("aop logging test!!");
}
@Around
어드바이스의 기능을 모두 포괄
대상 메서드를 감싸는 느낌으로 실행 전후 시점에 원하는 작업을 할 수 있다.
대상 메서드의 실행 제어 및 리턴 값 가공도 가능하다.
// 특정 어노테이션이 명시된 모든 메써드의 실행 전후로 끼어들 수 있다.
@Around("@annotation(someAnnotation)")
public Object doSomethingAround(final ProceedingJoinPoint joinPoint, final SomeAnnotation someAnnotation) {
// 대상 메써드 실행 전 끼어들어 실행할 로직을 작성
Object result = joinPoint.proceed();
// 대상 메써드 실행 후 끼어들어 실행할 로직을 작성, 리턴 값을 가공할 수 있다.
return result;
}
// 메써드 레벨에 특정 어노테이션이 명시된 모든 메써드의 실행 전후로 끼어들 수 있다.
@Around("@annotation(scheduled)")
public Object process(final ProceedingJoinPoint joinPoint, final Scheduled scheduled) throws Throwable {
// 클래스 레벨에 특정 어노테이션이 명시된 모든 메써드의 실행 전후로 끼어들 수 있다.
@Around("@within(org.springframework.web.bind.annotation.RestController) || @within(org.springframework.stereotype.Service) || @within(org.springframework.stereotype.Repository)")
public Object process(final ProceedingJoinPoint joinPoint) throws Throwable {
'Spring' 카테고리의 다른 글
Spring Boot + Flyway를 이용한 데이터베이스 마이그레이션 (0) | 2021.09.16 |
---|---|
Querydsl 설명 및 예제 (0) | 2021.09.15 |
Spring REST Docs 구축 예시 (0) | 2021.09.10 |
Spring REST Docs란? (0) | 2021.09.10 |
Spring Security와 JWT 사용 예제 (0) | 2021.09.10 |