이 글은 김영한 님의 스프링 입문 강좌 수강 후에 정리한 글입니다.
(https://www.inflearn.com/course/스프링-입문-스프링부트/dashboard)
AOP
● AOP가 필요한 상황
지금까지 구현한 회원 가입, 회원 조회 기능들의 소요 시간을 체크해보려고 한다.
MemberService 회원 조회 시간 측정 추가
package hello.hellospring.service;
import hello.hellospring.domain.Member;
import hello.hellospring.repository.MemberRepository;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import java.util.Optional;
@Transactional
public class MemberService {
public MemberService(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}
private final MemberRepository memberRepository;
//회원가입
public Long join(Member member){
long start = System.currentTimeMillis();
try{
validateDuplicatedMember(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");
}
}
private void validateDuplicatedMember(Member member) {
memberRepository.findByName(member.getName()).ifPresent(m->{
throw new IllegalStateException("이미 존재하는 회원입니다.");
});
}
}
기능들의 소요 시간을 체크하는 기능은 핵심 관리 사항이 아니고, 공통 관심 사항이다.
위 코드에서 볼 수 있듯이 시간 측정 로직과 비즈니스 핵심 로직이 섞여서 존재하기 때문에 유지보수가 어렵다.
만약에 시간 측정 로직을 변경할 일이 생기면 하나하나 찾아가면서 변경해야 한다.
또한 시간을 측정하는 로직을 별도의 공통 로직으로 만드는 것이 매우 어렵다. 그렇기 때문에 우리는 AOP를 사용해야 한다.
● AOP 적용
AOP는 Aspect Oriented Programming의 약자로 관점 지향 프로그래밍이라고 한다.
공통 관심 사항(cross-cutting concern)과 핵심 관심 사항(core concern)을 분리하여 프로그래밍하는 것을 뜻한다.
공통 관심 사항에 속하는 시간 측정 로직을 외부에서 적용을 원하는 클래스에 직접 주입하는 것이다.
1. 시간 측정 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 excute(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로 인식하기 위해서 @Aspect를 사용한다.
@Component를 사용하여 TimeTraceAop를 스프링 컨테이너에 빈으로 등록한다.
다른 방법으로 아래와 같은 코드를 SpringConfig에 따로 작성함으로써 스프링 컨테이너에 등록할 수도 있다.
@Bean
public TimeTraceAop timeTraceAop() {
return new TimeTraceAop();
}
@Around는 공통 관심 사항인 TimeTraceAop를 어디에 적용할 것인지 명시한다. 위 예시는 hello.hellospring 패키지 하위의 모든 클래스에서 적용하겠다는 의미이다.
이후에 서버를 동작시킨 후에 회원 목록 기능을 실행하면
START : execution(String hello.hellospring.controller.MemberController.list(Model))
START : execution(List hello.hellospring.service.MemberService.findMembers())
START : execution(List org.springframework.data.jpa.repository.JpaRepository.findAll())
END : execution(List org.springframework.data.jpa.repository.JpaRepository.findAll()) 211ms
END : execution(List hello.hellospring.service.MemberService.findMembers()) 219ms
END : execution(String hello.hellospring.controller.MemberController.list(Model)) 256ms
위와 같은 TimeTrace 기능이 구현이 됐음을 확인할 수 있다. 이를 통해 어느 부분에서 병목 현상이 발생하는지 확인할 수 있다.
2. AOP를 이용한 문제의 해결
- 회원가입, 회원 조회 등 핵심 관심사항과 시간을 측정하는 공통 관심 사항을 분리한다.
- 시간을 측정하는 로직을 별도의 공통 로직으로 만들었다.
- 핵심 관심 사항을 깔끔하게 유지할 수 있다.
- 변경이 필요하면 이 로직만 변경하면 된다.
- 원하는 적용 대상을 선택할 수 있다.
AOP를 활용하여 문제를 해결함으로써 위와 같은 장점을 가질 수 있다.
3. 스프링의 AOP 동작 방식 설명
AOP가 있을 때 가짜 memberService인 프록시 memberService를 생성하고, helloController는 가짜 memberService인 프록시를 호출한다. 프록시의 실행이 끝나면 jointPoint.proceed()를 통해 실제 memberService를 호출한다.
'개발 > 스프링 입문' 카테고리의 다른 글
(스프링 입문) 6. 스프링 DB 접근 기술 (0) | 2022.09.24 |
---|---|
(스프링 입문) 5. 회원 관리 예제 (웹 MVC 개발) (0) | 2022.09.24 |
(스프링 입문) 4. 스프링 빈과 의존관계 (0) | 2022.09.24 |
(스프링 입문) 3. 회원 관리 예제 (0) | 2022.09.24 |
(스프링 입문) 2. 스프링 웹 개발 기초 (0) | 2022.09.24 |