AOP 관련 용어
- Aspect
- 흩어진 관심사를 모듈화 한 것.
- Target
- Aspect를 적용하는 곳. 클래스, 메서드 등..
- Advice
- 실질적으로 어떤 일을 해야 할 지에 대한 것, 실질적인 부가기능을 담은 구현체
- Join Point
- Advice가 적용될 위치 혹은 끼어들 수 있는 시점. 메서드 진입 시점, 생성자 호줄 시점, 필드에서 꺼내올 시점 등 끼어들 시점을 의미.
- 참고로 스프링에서 Join Point는 언제나 메서드 실행 시점을 의미 한다.
- Point Cut
- Join Point의 상세한 스펙을 정의한 것. "A란 메서드의 진입 시점에 호출할 것"처럼 구체적으로 Advice가 실행될 시점을 정함.
AOP 적용 방법
1. 컴파일 타임 적용
-> 컴파일 시점에 바이트 코드를 조작하여 AOP가 적용된 바이트 코드를 생성하는 방법.
2. 로드 타임 적용
-> 순수하게 컴파일한 뒤, 클래스를 로딩하는 시점에 클래스 정보를 변경하는 방법
3. 런타임 적용
-> 스프링 AOP가 주로 사용하는 방법. A라는 클래스 타입의 Bean을 만들 때 A 타입의 Proxy Bean을 만들어 Proxy Bean이 Aspect 코드를 추가하여 동작하는 방법.
스프링 AOP
- 스프링에서 제공하는 스프링 AOP는 프락시 기반의 AOP 구현체이다.
- 프록시 객체를 사용하는 것은 접근 제어 및 부가 기능을 추가하기 위해서이다.
- 스프링 AOP는 스프링 Bean에만 적용할 수 있다.
- 모든 AOP 기능을 제공하는 것이 목적이 아닌, 중복 코드, 프록시 클래스 작성의 번거로움 등 흔한 문제를 해결하기 위한 솔루션을 제공하는 것이 목적이다.
- 스프링 AOP는 순수 자바로 구현되었기 때문에 특별한 컴파일 과정이 필요하지 않다.
스프링 AOP 구현
Spring AOP를 사용하기 위해서는 의존성을 추가해줘야 한다.
maven
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
gradle
implementation 'org.springframework.boot:spring-boot-starter-aop'
지금부터 구현할 기능은 타겟 메서드의 실행 시간을 측정해주는 로직이다.
@Component
@Aspect
public class PerfAspect {
@Around("execution(* com.example..*.EventService.*(..))")
public Object logPerf(ProceedingJoinPoint pjp) throws Throwable {
long begin = System.currentTimeMillis();
Object reVal = pjp.proceed();
System.out.println(System.currentTimeMillis() - begin);
return reVal;
}
}
스프링 AOP는 Bean에서만 동작한다고 했다.
따라서 @Component 어노테이션 등을 통해 스프링 Bean으로 등록해준 뒤 사용해야 한다.
@Aspect 어노테이션을 붙이면 해당 클래스가 Aspect라는 것을 명시해준다.
logPerf() 메서드는 @Around 어노테이션의 execution을 통해 Advice를 적용할 범위를 지정해줄 수 있다.
위의 코드를 예시로 들자면 com.example 밑의 모든 클래스에 적용하고,
EventService 밑의 모든 메서드에 적용하라는 뜻이다.
위와 같은 경로 지정 방식이 아닌 특정 어노테이션이 붙은 포인트에 해당 Aspect를 실행할 수도 있다.
@Component
@Aspect
public class PerfAspect {
@Around("@annotation(PerfLogging)")
public Object logPerf(ProceedingJoinPoint pjp) throws Throwable {
long begin = System.currentTimeMillis();
Object retVal = pjp.proceed();
System.out.println(System.currentTimeMillis() - begin);
return retVal;
}
}
위와 같이 @Around 어노테이션에 @annotation(PerfLogging)처럼 적용될 어노테이션을 명시할 수 있다. 그럼 해당 메서드를 적용시킬 특정 메서드에 @PerfLogging 어노테이션을 붙여주기만 하면 logPerf() 기능이 동작한다.
혹은 특정 Bean 전체에 해당 기능을 적용시킬 수도 있다.
// Aspect 정의
@Component
@Aspect
public class PerfAspect {
// 빈이 가지고있는 모든 퍼블릭 메쏘드
@Around("bean(simpleServiceEvent)")
public Object logPerf(ProceedingJoinPoint pjp) throws Throwable {
long begin = System.currentTimeMillis();
Object retVal = pjp.proceed();
System.out.println(System.currentTimeMillis() - begin);
return retVal;
}
}
위와 같이 @Around 어노테이션에 bean(simpleServcieEvent)처럼 적용될 빈을 명시할 수 있다.
그럼 해당 빈이 가지고 있는 모든 public 메서드에 해당 기능이 적용된다.
@Around 외에 타겟 메서드의 Aspect 실행 시점을 지정할 수 있는 어노테이션은 다음과 같은 것들이 있다.
- @Before : Advice 타겟 메서드가 호출되기 전에 Advice 기능 수행
- @After : 타겟 메서드의 결과에 관계없이 타겟 메서드과 완료되면 Advice 기능 수행
- @AfterRunning : 타겟 메서드가 성공적으로 결과값을 반환 한 후에 Advice 기능 수행
- @AfterThrowing : 타겟 메서드가 수행 중 예외를 던지면 Advice 기능 수행
- @Around : Advice가 타겟 메서드를 감싸 타겟 메서드 호출 전, 후에 Advice 기능 수행
'개발중 > Spring' 카테고리의 다른 글
[스프링] 프로젝트 생성 (1) (0) | 2022.10.29 |
---|---|
[SpringBoot] Spring Validation 기록 끄적 📸 (1) | 2022.10.22 |
[Spring] '스프링과 스프링부트의 차이점'을 모르고 스프링 할 줄안다고 하지말기 ! (2) | 2022.09.23 |
스프링 테스트 코드 작성하기 (1) | 2022.09.06 |
Response headers 에 Content-Disposition 안보임 😥Cors 관련인가 ? (0) | 2022.07.19 |