반응형
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-25. AOP 적용 본문

Java Spring/스프링 입문

[Java Spring] 1-25. AOP 적용

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

[Java Spring] 1-25. AOP 적용


1. 이러한 상황에 필요한 기술을 AOP (Aspect Oriented Programming) 라고 한다.

 

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

[Java Spring] 24. AOP가 필요한 상황 1. 모든 메소드의 호출 시간을 측정하고 싶다면? 직장 상사가 갑작스럽게 프로그램의 모든 메소드들의 호출 시간을 측정해오라는 업무지시를 한다. 프로그램에

develop247.tistory.com

 

2. 공통 관심 사항(cross-cutting concern) vs 핵심 관심 사항(core concern) 을 분리하는 기술을 말한다.

 

3. 시간 측정 로직을 한군데에 모으고, 내가 원하는 곳에 적용시키는 것을 가능하게 만드는게 AOP 이다.

 

4. main > java > hellospring 에 aop 하위 패키지 생성

 

5. aop 패키지 내에 TimeTraceAop 클래스 생성

 

6. 코드 작성

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");
        }
    }
}

- AOP 는 Aspect 어노테이션이 필요하다.

- 연결을 위해 Component 어노테이션을 추가한다.

- Around() 어노테이션은 어떤 메소드에 실행을 적용할지 추가하는 부분이다.

상기 코드에서는 hellospring의 모든 부분에 적용된다.

 

7. 빌드 후 테스트를 진행해보자.

- 회원 목록에 접속하니, 해당 사이트에 접속하기 위해 호출한 메소드들과 그 메소드들의 호출 시간을 결과로 확인할 수 있다.

 

8. 해결

- 회원가입, 회원 조회등 핵심 관심사항과 시간을 측정하는 공통 관심 사항을 분리한다.

- 시간을 측정하는 로직을 별도의 공통 로직으로 만들었다.

- 핵심 관심 사항을 깔끔하게 유지할 수 있다.

- 변경이 필요하면 이 로직만 변경하면 된다.

- 원하는 적용 대상을 선택할 수 있다.

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) {
        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);
    }
}

- 실제 MemberService 는 원래대로 돌아왔고, 깔끔하게 유지보수가 가능하며 측정 시간 외 기능을 추가할 때는 TimeTraceAop 클래스만 수정해주면 된다.

 

9. @Around 어노테이션 수정

- Around 어노테이션을 수정해서 내가 원하는 범위 내에서만 로직을 적용시킬 수도 있다.

 

10. 다시 빌드 후 테스트를 진행해보자.

- 실제 service 패키지 내에 있는 메소드들의 호출 시간만이 측정되어 출력되는 모습을 확인할 수 있다.

 

11. 작동원리

AOP 적용 전
AOP 적용 후

- 실제로 컨트롤러는 가상의 memberService 프록시를 호출한다.

- memberService 프록시를 호출 후 스프링 빈 호출이 끝나면, 그 때 proceed() 호출로 진짜 실제 memberService 를 호출해준다.

- 이는 간단한 코드를 추가하여 직접 확인해볼 수 있다.

- 실제 호출되는 클래스는 MemberService 가 아닌 SpringCGLIB 가 추가된 클래스임을 알 수 있다. 여기서 CGLIB 는 사용되는 라이브러리명이다.

 

12. 전체 의존관계

AOP 적용 전
AOP 적용 후

- 우리는 DI의 이점을 통해 AOP 기술을 사용할 수 있는 것이다.

반응형
Comments