반응형
Notice
Recent Posts
Recent Comments
Link
«   2024/05   »
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
Archives
Today
Total
05-19 00:03
관리 메뉴

ImJay

[Java Spring] 1-24. AOP가 필요한 상황 본문

Java Spring/스프링 입문

[Java Spring] 1-24. AOP가 필요한 상황

ImJay 2023. 1. 30. 13:09
반응형

[Java Spring] 1-24. AOP가 필요한 상황


1. 모든 메소드의 호출 시간을 측정하고 싶다면?

직장 상사가 갑작스럽게 프로그램의 모든 메소드들의 호출 시간을 측정해오라는 업무지시를 한다. 프로그램에 수천개의 메소드들이 존재한다고 가정하자. 우리는 수천개에 해당하는 메소드들의 처음과 끝마다 시간을 측정해주는 함수를 작성해야 한다.

그렇게 업무를 끝내서 초단위로 측정을 완료하니, 상사가 초단위는 정확히 확인이 안된다며 ms 단위로 측정을 다시 해보라고 한다. 우리는 수천개의 메소드를 또 다시 수정하는 과정을 반복해야 한다.

 

2. 상사의 요구사항대로 시간 측정 기능을 추가했다고 가정해보자 (MemberService.java)

시간측정이 추가된 로직

package hello.hellospring.service;

import hello.hellospring.domain.Member;
import hello.hellospring.repository.MemberRepository;
import hello.hellospring.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
public class MemberService {

    private final MemberRepository memberRepository;

    public MemberService(MemberRepository memberRepository) {
        this.memberRepository = memberRepository;
    }

    /**
     * 회원 가입
     */
    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");
        }
    }

    private void validateDuplicateMember(Member member) {
        memberRepository.findByName(member.getName())
                .ifPresent(m -> {
                    throw new IllegalStateException("이미 존재하는 회원입니다.");
                });
    }

    /**
     * 전체 회원 조회
     */
    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");
        }
    }

    public Optional<Member> findOne(Long memberId) {
        return memberRepository.findById(memberId);
    }
}

- 1번의 상황을 생각해본다면 위와 같은 작업을 몇천번 반복해야 한다. 물론, 템플릿 메서드 패턴으로 따로 빼줄 수야 있겠지만, 그것도 그것대로 매우 복잡해진다.

 

3. 테스트 확인

- 측정시간이 정상 출력됨을 확인할 수 있다.

 

4. 문제

4-1. 회원가입, 회원 조회에 시간을 측정하는 기능은 핵심 관심 사항이 아니다.

4-2. 시간을 측정하는 로직은 공통 관심 사항이다.

4-3. 시간을 측정하는 로직과 핵심 비즈니스의 로직이 섞여서 유지보수가 어렵다.

4-4. 시간을 측정하는 로직을 별도의 공통 로직으로 만들기 매우 어렵다.

4-5. 시간을 측정하는 로직을 변경할 때 모든 로직을 찾아가면서 변경해야 한다.

 

5. 공통 관심 사항(cross-cutting concern) vs 핵심 관심 사항(core concern)

우리는 이러한 문제를 공통 관심 사항과 핵심 관심 사항으로 분리하여야 한다.

 

6. 이러한 문제들을 AOP를 통해 해결해보자.

반응형

'Java Spring > 스프링 입문' 카테고리의 다른 글

[Java Spring] 1-26. 마무리  (0) 2023.01.30
[Java Spring] 1-25. AOP 적용  (0) 2023.01.30
[Java Spring] 1-23. 스프링 데이터 JPA  (0) 2023.01.30
[Java Spring] 1-22. JPA  (1) 2023.01.30
[Java Spring] 1-21. JDBC Template  (0) 2023.01.30
Comments