[25강]

2023. 2. 6. 14:56Spring 강의/section7

AOP 적용

  • AOP : Aspect Oriented Programming - 관점 지향 프로그래밍
  • 공통 관심 사항(cross-cutting concern) vs 핵심 관심 사항(core concern) 분리

이전처럼 모든 메소드마다 시간 측정 로직을 붙이는 게 아니라

원하는 메소드에 시간 측정 로직을 적용시킬 수 있다.

 

먼저 hello - hellospring2 밑에 aop란 패키지를 만들고 그 안에 TimeTraceAop 클래스를 만든다.

TimeTraceAop.class

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
package hello.hellospring2.aop;
 
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
 
@Aspect //붙여줘야 AOP로 쓸 수 있다.
@Component
public class TimeTraceAop {
 
    @Around("execution(* hello.hellospring2..*(..))")
    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");
        }
    }
}
cs
@Aspect : 붙어줘야 AOP로 쓸 수 있다.
@Component : 빈으로 등록시켜준다.
@Around : 해당 로직을 어떤 클래스에 사용할 것인지 정할 수 있다.
@Around("execution(* hello.hellospring2..*(..))") : hello.hellospring2 밑에 있는 모든 클래스에 적용시키겠다.

이제 MemberService 클래스는 핵심 로직만으로 깔끔하게 유지할 수 있다.

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
package hello.hellospring2.service;
 
import hello.hellospring2.domain.Member;
import hello.hellospring2.repository.MemberRepository;
import hello.hellospring2.repository.MemoryMemberRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
 
import java.util.List;
import java.util.Optional;
 
@Transactional //jpa를 쓰려면 항상 있어야 한다//data를 저장하고 변경할 때 필요
public class MemberService {
 
    private final MemberRepository memberRepository;
 
 
    public MemberService(MemberRepository memberRepository) {
        this.memberRepository = memberRepository;
    }
 
    /* 회원 가입 */
    public Long join (Member member){
 
            validateDuplicateMember(member); //중복회원 검증
            memberRepository.save(member);
            return member.getId();
 
    }
 
    private void validateDuplicateMember(Member member) {
        memberRepository.findByName(member.getName())
                .ifPresent(m -> {
                    throw new IllegalStateException("이미 존재하는 회원입니다.");
                });
    }
 
    /*전체 회원 조회 */
    public List<Member> findMembers(){
 
            return memberRepository.findAll();
    };
 
    public Optional<Member> findOne(Long memberId){
        return memberRepository.findById(memberId);
    }
}
cs

 

 

실행 결과

처음 서버를 실행했을 때

회원을 등록할 때

회원을 조회할 때

모든 시간을 알 수 있다.

 

해결

  • 회원가입, 회원 조회 등 핵심 관심사항과 시간을 측정하는 공통 관심 사항을 분리한다.
  • 시간을 측정하는 로직을 별도의 공통 로직으로 만들었다.
  • 핵심 관심 사항을 깔끔하게 유지할 수 있다.
  • 변경이 필요하다면 이 로직만 변경하면 된다.
  • 원하는 적용 대상을 선택할 수 있다.

 

스프링의 AOP 동작 방식 설명

AOP 적용 전 의존관계

바로 memberController에서 memberService를 호출한다.

 

AOP 적용후 의존관계

aop가 있으면 가짜 memberSerivce를 만들어낸다.

스프링 컨테이너에 스프링 빈을 등록할 때 가짜 스프링 빈을 앞에 세워둔다.

그리고 가짜 스프링 빈이 joinPoint.proceed()하면 그때 진짜 memberSerivce를 호출한다.

memberController가 호출하는 것은 프록시라는 기술로 발생하는 가짜 memberService이다.

 

AOP 적용 전 전체 그림

 

AOP 적용 후 전체 그림

컨테이너에서 스프링 빈을 관리하면 가짜를 만들어서 가짜를 진짜에 DI해주면 된다.

이게 바로 DI의 장점!

'Spring 강의 > section7' 카테고리의 다른 글

[24강]  (0) 2023.02.06