AOP는 공통의 관심 사항(cross-cutting concern)과 핵심 관심 사항(core concern)을 분리하기 위해 고안되었다.
위의 그림처럼 원하는 곳에 공통 관심 사항을 적용할 수 있는 것이다.
@Component// 스프링 빈으로 등록해줘야 한다.@Aspect// AOP를 사용하기 위한 애너테이션을 추가한다.publicclassTimeTraceAop {// 어디에 적용할지 결정한다.// hello.hellospring 패키지 아래에 있는 모든 클래스에 적용한다. @Around("execution(* hello.hellospring..*(..))")publicObjectexecute(ProceedingJoinPoint joinPoint) throwsThrowable {long start =System.currentTimeMillis();System.out.println("START: "+joinPoint.toString());try {// 다음 메서드로 진행한다.returnjoinPoint.proceed(); } finally {long finish =System.currentTimeMillis();long timeMs = finish - start;System.out.println("END: "+joinPoint.toString() +" "+ timeMs +"ms"); } }}
@ConfigurationpublicclassSpringConfig {privatefinalMemberRepository memberRepository;publicSpringConfig(MemberRepository memberRepository) {this.memberRepository= memberRepository; } @BeanpublicMemberServicememberService() {returnnewMemberService(memberRepository); }// @Component 대신 AOP를 사용한다는 점을 보여주기 위해 직접 빈을 등록해 사용하는 게 좋다. @BeanpublicTimeTraceAoptimeTraceAop() {returnnewTImeTraceAop(); }}
회원 가입, 조회 등 핵심 관심 사항과 시간 측정이라는 공통 관심 사항을 분리한다.
시간 측정 로직을 별도의 공통 로직으로 빼서 핵심 관심 사항을 깔끔하게 유지할 수 있다.
변경이 필요하면 이 로직만 변경할 수 있다.
원하는 적용 대상을 선택할 수 있다.
스프링의 AOP 동작 방식
AOP 적용 전 의존 관계
컨트롤러가 서비스를 의존하면서 필요한 메서드를 호출한다.
AOP 적용 후 의존 관계
프록시라는 가짜 서비스를 만들어서, 스프링이 실행될 때 컨테이너에 진짜 스프링 빈 말고 가짜 스프링 빈을 앞에 세운다. AOP 로직을 다 실행하고 joinPoint.proceed()로 가짜 스프링 빈이 끝나면 진짜 스프링 빈을 호출한다. 따라서 컨트롤러는 진짜 서비스가 아니라 가짜 서비스를 호출한다.