이 글은 김영한 님의 Infrean 강의를 학습한 내용을 정리하여 작성합니다.
AOP란 Aspect-Oriented Programming 의 약자로 관점 지향 프로그래밍이라 한다.
흩어진 Aspect들을 모아 모듈화 해주고 관심사 분리라는 개념을 가지며 객체지향 프로그래밍을 통해 더욱 객체지향적으로 만들어주는 기술이다.
AOP는 여러 곳에서 쓰이는 공통 기능을 모듈화하고, 쓰이는 곳에 필요할 때 연결함으로써, 유지 보수 혹은 재사용에 용이하도록 프로그래밍 한다.
AOP가 필요한 상황
- 모든 메소드의 호출 시간을 측정하고 싶다면?
- 공통 관심 사항 (cross-cutting concern) vs. 핵심 관심 사항 (core concern)
- 회원 가입 시간, 회원 조회 시간을 측정하고 싶다면?
예를 들어 MemberService 클래스 메소드 각각에 호출 시간을 측정하고 출력할 수 있도록 코드를 추가해본다.
@Transactional
public Long join(Member member) {
long start = System.currentTimeMillis();
// 같은 이름이 있는 중복 회원X
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");
}
}
MemberService 회원 조회 시간 측정 추가
테스트 결과
회원목록 참조 결과
문제
이렇게 수행할 경우 문제는 다음과 같다.
- 회원가입, 회원 조회에 시간을 측정하는 기능은 핵심 관심 사항이 아니다.
- 시간을 측정하는 로직은 공통 관심 사항이다.
- 시간을 측정하는 로직과 핵심 비지니스의 로직이 섞여서 유지보수가 어렵다.
- 시간을 측정하는 로직을 별도의 공통 로직으로 만들기 매우 어렵다.
- 시간을 측정하는 로직을 변경할 때 모든 로직을 찾아가면서 변경해야 한다.
이러한 문제점들을 해결하기 위해 AOP를 사용한다.
AOP 적용
- AOP: Aspect Oriented Programming
- 공통 관심 사항 (cross-cutting concern) vs. 핵심 관심 사항 (core concern) 분리
: 시간 측정 로직을 TimeTraceApp으로 분리하고 helloController, memberService, memberRepository 각각에 적용시킨다.
시간 측정 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
@Aspect
public class TimeTraceAop {
@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");
}
}
}
● @Around : 지정된 패턴에 해당하는 메소드의 실행되기 전, 실행된 후 모두에서 동작한다.
이 어노테이션이 붙은 메소드의 반환 값은 Object여야 한다.(지정된 패턴에 해당하는 메소드의 실행 결과를 반환해야 하므로)
execution
제일 기본적인 방법으로 특정 메서드를 지정하는 패턴을 작성할 수 있는 방법이다.
아래와 같은 형태로 작성되며 특정 메소드까지의 패턴을 딱 지정하는 표현식이다.
참고로 아래에 나올 다른 표현식들은 일부를 제외하고 execution으로 대체가 가능하다.
execution([접근제어자] 반환타입 패키지.패키지.패키지.패키지.클래스.메소드(인자))
출처: https://pamyferret.tistory.com/51
AOP 수행 결과
해결
- 회원가입, 회원 조회등 핵심 관심사항과 시간을 측정하는 공통 관심 사항을 분리한다.
- 시간을 측정하는 로직을 별도의 공통 로직으로 만들었다.
- 핵심 관심 사항을 깔끔하게 유지할 수 있다.
- 변경이 필요하면 이 로직만 변경하면 된다.
- 원하는 적용 대상을 선택할 수 있다.
스프링의 AOP 동작 방식 설명
AOP 적용 전 의존관계
AOP 적용 후 의존관계
memberController가 사용하는 memberService는 실제 memberService가 아닌 프록시 memberService에 해당한다.
AOP 적용 전 전체 그림
AOP 적용 후 전체 그림
'스프링 > 스프링 입문' 카테고리의 다른 글
스프링 DB 접근 기술 #2 (0) | 2022.03.06 |
---|---|
스프링 DB 접근 기술 #1 (0) | 2022.03.02 |
회원 관리 예제 - 웹 MVC 개발 (0) | 2022.03.01 |
스프링 빈과 의존관계 (0) | 2022.03.01 |
회원 관리 예제 - 백엔드 개발 (0) | 2022.02.28 |