AOP

박민서·2023년 5월 5일
0
  • AOP가 필요한 상황
    모든 메서드의 호출 시간을 측정하고 싶을 때
    공통 관심 사항(cross-cutting concern) vs 핵심 관심 사항(core concern)
    회원 가입 시간, 회원 조회 시간을 측정하고 싶을 때

  • MemberService 회원 조회 시간 측정 추가

package hello.hellospring.service;
@Transactional
public class MemberService {
 private final MemberRepository memberRepository;
 
  // DI(Dependency Injection): MemberRepository를 외부에서 주입하도록 변경
  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 " + timeMs + "ms");
 }
 }
 /**
 * 전체 회원 조회
 */
 public List<Member> findMembers() {
 long start = System.currentTimeMillis();
 try {
 return memberRepository.findAll();
 } finally {
 long finish = System.currentTimeMillis();
 long timeMs = finish - start;
 System.out.println("findMembers " + timeMs + "ms");
 }
 }
}
  • 문제
    회원가입, 회원 조회에 시간을 측정하는 기능은 핵심 관심 사항이 아니다.
    시간을 측정하는 로직은 공통 관심 사항이다.
    시간을 측정하는 로직과 핵심 비즈니스의 로직이 섞여서 유지보수가 어렵다.
    시간을 측정하는 로직을 별도의 공통 로직으로 만들기 매우 어렵다.
    시간을 측정하는 로직을 변경할 때 모든 로직을 찾아가면서 변경해야 한다.

  • AOP 적용
    AOP: Aspect Oriented Programming
    공통 관심 사항(cross-cutting concern) vs 핵심 관심 사항(core concern) 분리

  • 시간 측정 AOP 등록
package hello.hellospring.aop;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

@Component // AOP를 스프링 빈에 등록 
@Aspect // AOP 사용
public class TimeTraceAop {
// @Around: 공통 관심사 지정 (패키지 하위에 대해 모두 적용한다)
 @Around("execution(* hello.hellospring..*(..))")
 public Object execute(ProceedingJoinPoint joinPoint) throws Throwable {
 long start = System.currentTimeMillis();
 System.out.println("START: " + joinPoint.toString());
 try {
 return joinPoint.proceed();
 } finally {
 long finish = System.currentTimeMillis();
 long timeMs = finish - start;
 System.out.println("END: " + joinPoint.toString()+ " " + timeMs +
"ms");
 }
 }
}
  • AOP를 이용하면 핵심 관심 사항과 공통 관심 사항을 분리하여 별도의 공통 로직을 만들 수 있고 원하는 적용 대상을 선택할 수 있다.

  • AOP 적용 전에는 의존 관계에 따라서 호출한다.

스프링 컨테이너가 AOP가 적용된 클래스에 대해서 가짜 스프링 빈을 만들고 프록시를 통해 AOP를 실행한 뒤 join.Point.proceed()에서 진짜가 호출된다.

profile
ㅎㅇㅌ

0개의 댓글