김영한 님의 스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술 강의를 보고 작성한 내용입니다.
https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%EC%9E%85%EB%AC%B8-%EC%8A%A4%ED%94%84%EB%A7%81%EB%B6%80%ED%8A%B8/dashboard
모든 메소드의 호출 시간을 측정하고 싶다면?
공통 관심 사항(cross-cutting concern) vs 핵심 관심 사항(core concern)
회원 가입 시간, 회원 조회 시간을 측정하고 싶다면?
< MemberService >
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");
}
}
문제점
위처럼 모든 메소드에 하나씩 시간을 측정하는 코드를 추가해야함
회원가입, 회원 조회에 시간을 측정하는 기능은 핵심 관심 사항이 아니다
시간을 측정하는 로직은 공통 관심 사항이다 ( not 핵심 )
시간을 측정하는 로직과 핵심 비즈니스의 로직이 섞여서 유지보수가 어렵다
시간을 측정하는 로직을 별도의 공통 로직으로 만들기 매우 어렵다
시간을 측정하는 로직을 변경할 때 모든 로직을 찾아가면서 변경해야 한다
AOP: Aspect Oriented Programming ( 관점 지향 프로그래밍 )
핵심 관심 사항과 공통 관심 사항을 분리해서 작성해야함
공통 관심 사항 로직을 작성하고 원하는 곳에 적용
< TimeTraceAop >
@Aspect
@Component
public class TimeTraceAop {
@Around("execution(* com.ghkwhd.project_2.*(..))")
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");
}
}
}
@Aspect
: 해당 클래스가 AOP를 나타내는 클래스임을 나타냄
만들어진 AOP는 스프링 빈으로 등록해야하기 때문에 @Component
를 사용 ( 컴포넌트 스캔을 이용 )
joinPoint.proceed()
: 실제 메서드를 호출하고 return 되는 데이터를 받는다
joinPoint.toString()
: 어떤 메서드를 수행하는지 반환해줌
@Around
: AOP를 어디에 적용할 것인지 타켓팅
@Around("execution(* com.ghkwhd.project_2.*(..))")
: 패키지 하위에는 모두 적용하는 코드
< SpringConfig >
@Bean
public TimeTraceAop timeTraceAop() {
return new TimeTraceAop();
}
@Component
를 붙이지 않는 경우에 사용 ( 컴포넌트 스캔을 사용하지 않는 경우 )AOP를 작성하고 어디에 적용할 것인지를 지정하면 spring은 가짜(프로시)를 만든다
Spring Container는 스프링 빈을 동록할 때, 실제 스프링 빈이 아닌 가짜(프록시) 스프링 빈을 만들어 앞에 세워놓는다
가짜(프록시) 스프링 빈이 끝나면 joinPoint.proceed()
를 통해 실제 스프링 빈을 호출
ex> MemberController가 호출하는 것은 실제 MemberService가 아닌 프록시 MemberService
프록시를 통해 AOP가 실행
이전 게시글 참고 : https://velog.io/@hj_/Spring-Boot-30.-AOP-%EB%B6%80%EA%B0%80-%EA%B8%B0%EB%8A%A5-%EC%A3%BC%EC%9E%85