- mysql
- spring security 6
- 스프링부트
- AWS
- 1차원 배열
- 프로그래머스
- spring boot
- 문자열
- Git
- @transactional
- java
- sql
- string
- Docker
- jpa
- spring mvc
- 자바
- spring
- DI
- 데이터베이스
- SSL
- session
- PYTHON
- select
- 스프링
- Django
- nginx
- ORM
- springboot
- join
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
개발하는 자몽
스프링 부트 공부 (10), AOP 본문
이 글은 아래 강의를 기반으로 작성됩니다.
AOP가 필요한 상황
AOP는 언제, 왜 쓰는지를 알면 어렵지 않다. 그렇다면 언제 쓰고 싶은 걸까? 다음과 같은 상황이 주어졌다고 하자.
- 모든 메소드의 호출 시간을 측정하고 싶어
- 공통 관심 사항(cross-cutting concern) VS. 핵심 관심 사항(core concern)
- 회원 가입 시간, 회원 조회 시간을 측정하고 싶어
모든 메소드의 호출 시간을 측정하고 싶어서 초 단위로 측정을 했다. 하지만 갑자기 ms 단위로 변경해야 하는 상황이 오면 호출 시간 측정 로직을 작성한 모든 메소드를 일일이 전부 고쳐야 한다. 문제는 더 있다.
- 회원 가입, 회원 조회에 대해 시간을 측정하는 기능은 핵심 관심 사항이 아님
- 시간을 측정하는 로직은 공통 관심 사항임
- 공통적으로 여러 메소드에 대해 시간을 측정하는 것이므로.
- 시간을 측정하는 로직과 핵심 비즈니스의 로직이 섞여서 유지보수가 어려움
- 시간을 측정하는 로직을 별도의 공통 로직으로 만들기 매우 어려움
- 시간을 측정하는 로직을 변경할 때 모든 로직을 찾아가면서 변경해야 함(위에서 언급한 문제)
AOP 적용
AOP는 Aspect Oriented Programing의 약자로, 관점 지향 프로그래밍을 뜻한다. 이는 어떤 로직을 기준으로 공통 관심 사항, 핵심 관심 사항으로 나누어서 모듈화 하겠다는 것이다. 여기서 모듈화란 어떤 공통된 로직이나 기능(위에서 언급한 시간 측정 로직/기능)을 하나의 단위로 묶는 것을 말한다.
이전에는 시간 측정 로직을 모든 메소드에 각각 적용했다. 하지만 AOP를 사용하면 공통 관심 사항인 시간 측정 로직을 한 곳에 다 모으고 원하는 곳에 적용할 수 있다.
TimeTraceAop
aop 패키지를 따로 하나 만들고 그 안에 TimeTraceAop 클래스를 하나 만든다. AOP를 사용하기 위해선 @Aspect가 필요하다.
@Aspect //해당 어노테이션이 있어야 AOP로 사용가능
@Component //이거로 해도 되는데 AOP를 쓴다는 것을 명시적으로 알리기 위해서 config 파일에 넣어둠(쨋든 빈등록을 해야함)
public class TimeTraceAop {
//공통관심사항을 어디에 적용할 것인가 -> @Around로 타겟팅
@Around("execution(* hello.hellospring..*(..))") // 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");
}
}
}
이제 스프링 빈으로 등록해야 한다. ComponentScan인 @Component 또는 직접 빈으로 등록해야 하는데 AOP를 쓴다는 것을 인지할 수 있게 직접 빈으로 등록하는 것이 좋다.
이번에는 공통 관심 사항을 타겟팅하기 위해 @Around를 사용하자.
→ @Around("execution(접근제어자 반환형 패키지를 포함한 클래스 경로 (메소드 파라미터))")
위 코드에서는 *로 시작하는데 이는 접근제어자와 반환형 모두를 상관하지 않고 적용하겠다는 의미이다. hello.hellospring..*는 hello.hellospring 패키지 하위 클래스에는 모두 적용을 한다는 의미이며, (..)은 메소드의 파라미터가 몇 개가 존재하던지 상관없이 실행하는 경우를 의미한다. 해당 어노테이션에 대한 정확한 정보는 아래 링크를 참고하자.
SpringConfig
마지막으로 설정 파일에 TimeTraceAop를 스프링 빈에 직접 등록하자.
@Bean
public TimeTraceAop timeTraceAop() {
return new TimeTraceAop();
}
실행
이렇게 코드를 작성하고 실행시키면 콘솔창에서 AOP가 적용된 메소드에 대해 원하는 단위(여기에서는 ms)로 측정된 호출 시간이 출력된 것을 확인할 수 있다.
AOP를 적용함으로써 해결된 사항들
- 핵심 관심 사항과 시간을 측정하는 공통 관심 사항 분리
- 시간을 측정하는 로직을 별도의 공통 로직으로 만듦
- 핵심 관심 사항을 깔끔하게 유지할 수 있게 됨
- 변경 필요시 이 로직만 변경하면 됨
- 적용을 원하는 대상을 선택할 수 있음
스프링 AOP 동작 방식
AOP 적용 전 의존관계는 memberController가 memberService를 의존하고 있고, memberController에서 memberService 메소드를 호출하는 것이었다.
AOP 적용 후 의존관계(이때 타겟은 hello.hellospring.serivce)를 적용하면, 스프링 컨테이너가 가짜 memberService(프록시 memberService, 가짜 스프링 빈)를 만든다. 그리고 프록시 memberSerivce에서 joinPoint.proceed()를 실행하면 실제 memberService가 호출된다.
따라서 memberController가 호출하는 것은 진짜 memberService가 아닌 프록시 기술로 발생하는 가짜 memberService이다.
마무리
위 강의를 기반으로 한 포스팅 시리즈는 이 게시글로 끝이다. 다음에는 유료 강의 시리즈를 들고와야지.
참고
'Java > Spring' 카테고리의 다른 글
[Spring]빈 등록과 의존관계 주입 (0) | 2022.08.04 |
---|---|
AnnotationConfigApplicationContext와 static class (0) | 2022.08.03 |
스프링 부트 공부 (9), 스프링 DB 접근 기술 (0) | 2022.03.12 |
스프링 부트 공부 (8), 회원관리 예제 - 웹 MVC 개발 (0) | 2022.03.06 |
스프링 부트 공부 (7), 스프링 빈과 의존관계 - 2 (0) | 2022.02.23 |