제육's 휘발성 코딩
Published 2021. 7. 26. 03:06
Spring AOP 🔷 Spring/basic
반응형

AOP란?

  • Spring은 Spring Triangle이라고 부르는 세 가지 개념을 제공해준다. 각각 IoC, AOP, PSA를 일컫는다.
  • AOP는 Aspect Oriented Programming의 약자로 '관점 지향적인 프로그래밍'이라는 의미이다.
  • AOP의 핵심 개념은 관심사의 분리이다. (Tracing, Exception, Transction 등)
  • AOP 사용 시 코드 분산, 코드 꼬임 등을 처리하여 간결한 구조를 만들 수 있다.
  • ※ PSA (Portable Service Abstraction) : 추상화 계층을 사용하여 어떤 기술을 내부에 숨기고 개발자에게 편의성을 제공해주는 것

AOP 기능

  • @Aspect : 흩어진 관심사를 모듈화, Aspect 클래스임을 정의
  • Target : Aspect를 적용하는 곳 (클래스, 메서드 등 )
  • Advice : 실질적으로 어떤 일을 해야할 지에 대한 것, 실질적인 부가기능을 담은 구현체
    • Advice 동작시점
    • @Before : 메서드 실행 전에 동작
    • @After : 메서드 실행 후에 동작
    • @After-returning : 메서드 정상 실행 후에 동작
    • @After-throwing : 예외가 발생한 후에 동작
    • @Around : 메서드 호출 이전, 이후, 예외 발생 등 모든 시점에 동작
  • JointPoint : Advice가 적용될 위치, 끼어들 수 있는 지점. 메서드 진입 지점, 생성자 호출 시점, 필드에서 값을 꺼내올 때 등 다양한 시점에 적용가능
  • PointCut : JointPoint의 상세한 스펙을 정의한 것. 'A란 메서드의 진입 시점에 호출할 것'과 같이 더욱 구체적으로 Advice가 실행될 지점을 정할 수 있음

AOP 예시1

Connection connection = dataSource.getConnection(); 

try (connection) {
    connection.setAutoCommit(false);   
    m.select();
    m.update()
    m.insert();
    m.delete();
    connection.commit(); 
} catch (SQLException e) {
    connection.rollback();
}
  • CRUD 처리할 때마다 예외처리 및 중복 코드 발생
  • @Transactional public String sql() { m.select(); m.update(); m.insert(); m.delete(); }
  • @Transactinal : db connect를 통해 로직들을 하나의 트랜잭션으로 관리 (모든 로직이 정상적으로 끝나야 commit)

AOP 예시2 (시간 측정 기능)

public List<Member> findMember() {
        long start = System.currentTimeMillis(); // 시간측정 로직
        try {
            return memberRepository.findAll(); //핵심 로직 
        } finally {
            long finish = System.currentTimeMillis(); // 시간측정 로직
            long timeMs = finish - start; // 시간측정 로직
            System.out.println("timeMs = " + timeMs + "ms"); 
        }

    }
  • 시간 측정 로직은 공통 관심 사항이다.
  • 시간 측정 기능은 핵심 관심 사항이 아니다.
  • 시간 측정 로직과 핵심 비즈니스 로직이 섞여 유지보수가 어렵다.
  • 별도의 공통 로직으로 만들기 매우 어렵다.
  • 모든 로직을 찾아가면서 변경해야 한다.
  • 공통 관심 사항(cross-cutting concern) :시간 측정 로직 vs 핵심 관심 사항(core concern) 분리 필요

AOP 적용

sec7캡처1

AOP 적용 코드

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;

@Component //컴포넌트 스캔을 사용하거나 (빈등록), Configuration 에 직접 빈등록 (이 방법을 주로 선호) 
@Aspect //AOP 적용 어노테이션 
public class TimeTraceAop {
    //hellospring 패키지의 하위 모두에 적용 시키겠다.
    @Around("execution(* hello.hellospring..*(..))")
    // 가짜 Bean 통해 프록시를 생성 후 JoinPoint로 진짜 Bean으로 연결
    public Object execute(ProceedingJoinPoint joinPoint) throws Throwable {
        long start = System.currentTimeMillis();
        System.out.println("START: " + joinPoint.toString()); //joinPoint.toString(): 실행위치 
        try {
            return joinPoint.proceed(); //인라인으로 합침 (Object result = joinPoint.proceed(); + return result;)
        } finally {
            long finish = System.currentTimeMillis();
            long timeMs = finish - start;
            System.out.println("END: " + joinPoint.toString()+ " " + timeMs + "ms");
        }
    }
}
  • 공통 관심 사항(cross-cutting concern) :시간 측정 로직 vs 핵심 관심 사항(core concern) 분리
  • 유지보수 간단
  • @Around 에서 적용하지 않을 곳도 추가 지정이 가능하다.
    EX) @Around("execution(* hello.hellospring.service..*(..))") : service 하위만 적용

AOP 동작 방식 (의존 관계)

  • 프록시 방식의 AOP (DI가 가능하니까 프록시 방식이 가능 (전달할 대상이 누군지 상관 없음)), 실제 자바코드를 넣는 AOP 방식도 있다.
  • 프록시 : 프록시 객체는 원래 객체를 감싸고 있는 가짜 객체이다.
  • 프록시패턴 : 가짜 객체가 원래 객체를 감싸서 client의 요청을 처리하게 하는 패턴이다.

※ 프록시 패턴을 쓰는 이유는 접근을 제어하고 싶거나, 부가 기능을 추가하고 싶을 때 사용한다.
※ .getClass()를 이용해 로그 출력해보면 $$EnhancerBySpringCGLIB$$~ 통해 프록시 적용을 확인할 수 있다.

sec7캡처2

  • 전체 의존 관계

sec7캡처3


본 포스팅은 인프런 김영한님 강의(스프링 입문)를 토대로 정리한 내용입니다.

반응형
profile

제육's 휘발성 코딩

@sasca37

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요! 맞구독은 언제나 환영입니다^^