Spring/AOP
AOP란?
푸라멘
2024. 4. 14. 23:50
AOP(Aspect Oriented Programming) 란?
관점 지향 프로그래밍이라고 불리며
어떤 로직을 기준으로 핵심적인 관점(core concerns), 부가적인 관점(cross-cutting concerns)으로 나누어 모듈화 하는 방법을 말한다.
AOP 예시
회원가입기능을 만들고 회원가입 기능의 성능을 확인하기 위해 소요시간이 얼마나 걸렸는지 계산하는 로직을 추가하고 싶다.
public class MemberService {
private MemberRepository memberRepository;
@Autowired
public MemberService(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}
public Long join(Member member) {
long start = System.currentTimeMillis();
try {
validateDuplicateMember(member);
memberRepository.save(member);
return member.getId();
} finally {
long finish = System.currentTimeMillis();
long timeMs = finish - start;
System.out.println("join time => " + timeMs + "ms");
}
}
}
위 코드는 다음과 같은 문제가 있다.
- 시간을 측정하는 로직(cross-cutting concerns) 과 핵심 로직(core concerns)이 섞여 유지보수가 어렵다.
- join 외 다른 메서드에 시간측정 로직을 추가하고 싶다면 메서드마다 하나하나 시간 측정로직을 추가해야하고 시간측정로직의 변경이 있다면 모든 메서드를 찾아가 로직 변경을 해줘야한다.
- 시간을 측정하는 공통로직을 별도의 공통 로직으로 만들기 매우 어렵다.
AOP 적용
@Aspect
@Component
//bean 등록을 해줘야한다.
public class TimeTraceAop {
// @Around로 target을 정한다.
@Around("execution(* com.example.bootpractice..*(..))")
public Object execute(ProceedingJoinPoint joinPoint) throws Throwable {
long start = System.currentTimeMillis();
try {
// 실행할 실제 객체의 메서드 실행
Object result = joinPoint.proceed();
return result;
} finally {
long finish = System.currentTimeMillis();
long timeMs = finish - start;
System.out.println("END : " + joinPoint.toString() + " " + timeMs + " ms" );
}
}
}
@Aspect
- AOP역할을 할 클래스를 선언하기 위한 어노테이션
- advice와 pointcut 이 함께 존재
- advice : 프록시가 호출하는 부가 기능, 프록시가 적용할 cross-cutting concerns 로직 이다. (execute 메서드 부분 )
- pointcut : 필터링 할 위치를 지정하느 필터링 로직, 어디에 cross-cutting concerns를 적용할지 결정 (@Around 부분)
@Around
- 메서드 호출 전후로 advice를 수행
- @Before(호출 전)이나 @After(호출 후)으로 이용해서 지정할 수 있다.
- pointcut 표현식으로 adivce를 적용할 method를 명시
ProceedingJointPoint
- 호출 되는 대상 객체에 대한정보, 실행되는 메서드에 대한 정보 등이 들어있는 클래스
- 원리
- SpringBoot의 자동 설정으로 AnnotationAwareAspectAutoProxyCreator라는 자동프록시 생성기가 빈으로 등록됨
- 자동프록시 생성기가 @Aspect가 붙은 클래스를보고 Advisor로 변환해 저장
- 변환된 Advisor를 보고 pointcut의 대상이되는 메서드를 ProxyFactory에 인자로 넘겨 자동으로 프록시 생성
- 생성된 프록시가 메서드 호출시 ProceedingJoinPoint 객체 생성 후 Advice에 전달
AOP 동작 방식
- Controller가 MemberService에 Method를 호출하면 프록시 MeberService를 호출하고 프록시 MeberService가 실제 MemberSerivide의 메서드를 호출한다.
- 즉, Meberservice를 주입 받을 때 @Aspect로 인하여 생성된 프록시 MemberService를 실제 MeberService 대신 주입받아 사용한다. (DI)
- 다음은 MemberController에 MemberSerivice를 주입 할 떄 MemberService.Class를 출력해 본 내용이다.
AOP 적용 전 MemberService
- MeberService가 정확히 출력되었다.
AOP 적용 후 MemberService
- MemberService&&SpringCGLIB$$0으로 출력되었다. ( SpringCGLIB는 Proxy객체를 생성해주는 라이브러리이다.)
참고자료
- https://ktko.tistory.com/entry/Spring-AOP%EA%B5%AC%ED%98%84Aspect-%EC%96%B4%EB%85%B8%ED%85%8C%EC%9D%B4%EC%85%98-%EC%82%AC%EC%9A%A9
- https://velog.io/@ds02168/37%EC%9D%BC%EC%B0%A8-AOP-Advice-PointCut
- https://junior-datalist.tistory.com/282
- https://owin2828.github.io/devlog/2019/12/30/spring-7.html
- https://pingpongdev.tistory.com/24