주저리
😃 안녕하세요! Undefind입니다.
이번에 취준진담을 개발하면서 Spring AOP를 처음으로 사용해 로깅을 해보았습니다.
개발을 진행하며 트랜잭션 로깅, 메로리 로깅 등을 사용하였던 느낌을 받아, 무작정 사용하기 시리즈를 포스팅으로 정하여 공부하고 실제로 리팩토링 하려고 합니다.
1. Spring의 장점 및 특징
2. Spring AOP의 개념 (어노테이션 정리)
3. Spring AOP의 특징
4. 개발하고 있는 어플리케이션의 간단한 AOP 예제
본 포스팅에선 Spring AOP의 중요성 부터, 왜 Spring AOP를 사용하는지 그리고 어떻게 무작정 사용하는지 등을 순서대로 말씀드리겠습니다!
Spring Framework
우리는 Spring이라고 부르지만 "Spring Framework"라고 하는 것이 정확한 표현이다.
자바 엔터프라이즈 개발을 위한 "오픈 소스" 애플리케이션 프레임워크로 종속 객체를 생성해주고, 조립할 수 있는 프레임워크이다.
이 모든것을 이해하는 데에는 인프런 강의의 김영한씨의 Spring 기초 강의가 도움을 주었다.
꼭 결재해서 보는 것을 추천한다. 😏
AOP(Aspect Oriented Programming) 관점지향 프로그래밍
어떤 로직을 기준으로 핵심적인 관점, 부가적인 관점으로 나누어 보고 그 관점을 기준으로 각각 모듈화하여 개발하는 프로그래밍이다.
다음과 같이 소스 코드 상에서 반복되는 코드들을 흩어진 관심사(Crosscutting Concerns)라고 부른다.
위와 같이 흩어진 관심사를 Aspect로 모듈화하고 핵심적인 비즈니스 로직에서 분리하여 재사용하겠다는 것이 AOP의 취지이다. (Spring AOP를 사용하는 목적)
다양한 어노테이션이 많다. 😭 될 수 있으면 다 이해하고 외우는 것이 좋다.
모든 어노테이션은 한번 읽어보면 개발할 수 있다!. 글이 많다고 포기하지 말고 정독하기!! 😳
프록시
이번 프로젝트에서는 Maven을 사용하여 프로젝트의 모듈 의존성을 관리하였다.
Spring AOP를 이용하여 함수의 시간 체크를 하려고한다.
함수 시간 체크는 개발에 있어서 아주 중요한 기능이다.
아주 기본적인 기능,,,,
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
이렇게 모듈 의존성을 추가해주었다면 설정 끝이다. 개발 완료!! 🐱
어노테이션으로 내가 원하는 패키지에 있는 함수만 실행하게 구성하였습니다.
Pointcut 어노테이션을 패키징으로 처리할 수 있습니다.
관련 포스팅 : 다양한 Pointcut
@Aspect // ---------------------------------------- (1)
@Component // ------------------------------------ (2)
@Slf4j // --------------------------------------- (3)
public class TimeCheckAop {
private long beforeTime;
private long afterTime;
@Pointcut("@annotation(com.gsm.chwijuntime.aop.timecheck.TimeCheck)") // -------- (4)
public void TimeCheck() {}
@Before("TimeCheck()") // ------------- (5)
public void before(JoinPoint joinPoint) {
beforeTime = System.currentTimeMillis();
}
@AfterReturning(pointcut = "TimeCheck()", returning = "result") // ---------- (6)
public void AfterReturning(JoinPoint joinPoint, Object result) {
afterTime = System.currentTimeMillis();
log.info("코드 수행 시간(ms) : " + (afterTime - beforeTime) + "ms");
log.info("코드 수행 시간(s) : " + ((afterTime - beforeTime)/1000.0) + "s");
log.info("result = " + result); // ------------- (7)
}
}
(1) : 흩어진 관심사를 모듈화하기 위해 선언, 여기서는 시간 체크 클래스입니다.
(2) : Spring Bean에 등록하기 위해 선언한다.
(3) : log를 사용하기 위해 선언한다.
(4) : JointPoint의 상세한 스펙을 정의한 것. 'TimeCheck란 어노테이션의 진입 시점에 호출할 것'과 같이 더욱 구체적으로 실행 시점을 정하기 위해 선언한다.
(5) : 어드바이스 타겟 메소드가 호출되기 전에 어드바이스 기능을 수행, 여기서는 메소드가 실행할 시점에 시간을 저장한다.
(6) : 타겟 메소드가 성공적으로 결과값을 반환 후에 어드바이스 기능을 수행, 여기서는 메소드가 끝난 시점에 시간을 저장한다. (returning은 타겟 메소드의 리턴 값이 그대로 전달되어 (7) 라인에 리턴된 값이 출력된다.)
@MemoryCheck @TimeCheck // --------- (1)
@Override
public Member findMember(MemberLoginDto memberLoginDto) {
Member member = memberRepository.findByMemberEmail(memberLoginDto.getMemberEmail()).orElseThrow(EmailNotFoundException::new);
boolean check = passwordEncoder.matches(memberLoginDto.getMemberPassword(), member.getMemberPassword());
if(!check) {
throw new IncorrectPasswordException();
}
return member;
}
(1) : 위에서 만든 커스텀 어노테이션이다. 해당 메소드를 실행하게 되면 AOP가 적용된다. Before 어노테이션으로 시작 시점을 저장하고 AfterReturning 어노테이션으로 종료 시점을 저장하여 메소드의 실행 시간을 구해준다. 참고로 Return된 값은 MemberLoginDto이다.
이번 포스팅에선 Sprign AOP의 개념과, Spring AOP를 사용하여 메소드의 시간을 측정하는 것을 구현해 보았습니다. AOP는 부가 기능을 분리해 모듈화 함으로써 재사용이 가능한 코드를 만드는 것이 목적입니다.
성장 과정이 궁금하시다면 깃허브 팔로우 한번씩 부탁드릴께요 😃
다음 무작정 따라하기 주제는 무엇으로 할까요??? 기대 많이 해주세요 😏쀼쀼