스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술을 들으며 정리하는 POST입니다.
전체적인 흐름
- Spring Project 생성
- Spring boot로 웹 서버 실행
- 회원 도메인 개발
- 웹 MVC 개발
- DB 연동 - JDBC, JPA, Spring data JPA
- 테스트 케이스 작성
service/MemberService.java
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");
}
}
try - finally
문을 이용하여 예외가 발생해도 호출 시간을 측정할 수 있도록 한다.// 전체 회원 조회
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");
}
}
findMembers
method의 시간 확인을 위해 스프링을 동작시켜 회원 목록을 확인하고자 하면, 아래와 같은 결과를 볼 수 있다.문제
Aspect Oriented Programming
aop/TimeTraceAop.java
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;
@Aspect
@Component
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");
}
}
}
@Aspect
annotation이 필요하다.joinPoint
라는 중간 intercept 지점에 정보가 담긴다. @Around
annotation으로, 작성한 공통 관심 사항인 TimeTraceAop
를 어디 적용시킬 것인지 명시한다.@Around("execution(* hello.hellospring..*(..))")
는 hello.hellospring
package 하위에 있는 모든 class에 적용한다는 의미@Component
annotation을 사용하여 컴포넌트 스캔을 할 수도 있지만, AOP는 특별한 기능이기 때문에 SpringConfig
에서 아래와 같이 따로 작성할 수도 있다.SpringConfig
@Bean
public TimeTraceAop timeTraceAop() {
return new TimeTraceAop();
}
이제 서버를 동작시켜 회원 목록 기능을 작동시키면,
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()) 64ms
END: execution(List hello.hellospring.service.MemberService.findMembers()) 78ms
END: execution(String hello.hellospring.controller.MemberController.list(Model)) 89ms
문제 해결
MemberService.java
)Dependency Injection이 기반으로 작용하기에 AOP의 동작이 가능하다.
memberService
= 프록시 memberService
을 생성한다.joinPoint.proceed()
를 통해 실제 memberService
를 호출한다.helloController
는 실제 memberService
가 아닌 프록시 기술로 생성된 가짜 memberService
를 호출한다.AOP, 프록시 기술