Spring

Spring AOP란?

Beekei 2021. 9. 11. 00:23
반응형

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 {
반응형