AOP는 Aspect 단위로 코드를 나누는 것을 의미합니다. 서비스 로직에서 로깅이나 트랜잭션은 공통적인 기능입니다. 이러한 공통적으로 기능하는 문제를 모듈화하는 것이 cross-cutting 입니다.
Aspect
: 공통적으로 기능하는 문제에 대한 모듈화Join point
: Aspect
의 대상이 되는 특정 메서드Point Cut
: Join point
에 대한 지칭 Advice
: Join point
에서 Aspect
가 실행할 조치
@Transactional
은 대표적인 AOP의 활용임
@Transactional
과 동일하게 메서드 앞 뒤로, 어노테이션을 붙여 작동하는 로깅 Aspect를 구현해보자
implementation 'org.aspectj:aspectjweaver'
@Configuration
@EnableAspectJAutoProxy
public class AppConfig {
}
@EnableAspectJAutoProxy
spring에 AOP 프록시를 허용할 것임을 알려줌Join Point를 나타내기 위한 어노테이션을 만들자
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.CLASS)
public @interface CustomLogger {
}
@Target(ElementType.METHOD)
: 메소드에 붙이는 어노테이션임
@Retention(RetentionPolicy.CLASS)
: 바이트 코드에 기록됨
💬 아마도 Spring AOP 프록시가 표준 JDK Dynamic Proxy라서 바이트 코드까지만 기록되도 되는 것 같다.
@Slf4j
@Aspect
@Component
public class LoggingAspect {
@Around("@annotation(CustomLogger)")
private void logger(ProceedingJoinPoint joinPoint) throws Throwable {
String methodName = joinPoint.getSignature().getName();
log.info(joinPoint.getTarget() + " call " + methodName);
joinPoint.proceed();
log.info(joinPoint.getTarget() + " end " + methodName);
}
}
@Aspect
: Aspect 클래스임@Component
: 빈에 등록하는 클래스임@Around
: Join Point 앞 뒤로 실행되는 모듈임@annotation(CustomLogger)
: @CustomLogger
를 붙인 메서드는 다 Join Point임joinPoint.proceed();
: Join Point가 실행되는 시점을 지정함로깅 Aspect를 서비스 코드에 적용해보자
@Slf4j
@Component
public class SomeService {
@CustomLogger
public void someLogic() throws SQLException {
log.info("do biz logic");
}
}
@CustomLogger
: 아까 생성한 어노테이션을 붙여 Join Point임을 나타냄someLogic()
호출시 아래와 같이 메서드 앞뒤로 로깅 Aspect가 작용하는 것을 확인할 수 있다.
@SpringBootApplication
public class SomeApplication implements ApplicationRunner {
@Autowired
SomeService someService;
public static void main(String[] args) {
SpringApplication.run(SomeApplication.class, args);
}
@Override
public void run(ApplicationArguments args) throws Exception {
someService.someLogic();
}
}
Aspect Oriented Programming with Spring
Kotlin으로 Spring AOP 극복하기!