매일 까먹는 스프링 개념 정리 3

2018-09-14

1. AOP

1-1. AOP란

  • 관점 지향 프로그램(Aspect Oriented Programming)
  • 프로그래밍을 하다 보면 공통적인 기능이 발생하는데, 이러한 공통 기능을 모든 모듈에 적용하기 위한 방법으로 상속을 통한 방법이 있다
  • 하지만 자바에는 다중 상속이 불가하므로 다양한 모듈에 상속 기법을 통한 공통 기능 부여에는 한계가 있다.
  • 그리고 기능 구현 부분에 핵심 기능 코드와 공통 기능 코드가 섞여 있어 효율성이 떨어진다 (ex. log)
  • 위의 상속을 통한 방법에는 한계가 있어 AOP가 등장했다.
  • AOP 방법은 핵심 기능과 공통 기능을 분리 시켜 놓고, 공통 기능을 필요로 하는 핵심 기능들에서 사용하는 방식이다.


1-2. 용어

  • Aspect: 여러 객체에 공통으로 적용되는 공통 관심 사항으로 Advice와 JointPoint를 합친 것 (트랜잭션이나 보안)
  • Advice: 언제 공통 관심 기능을 핵심 로직에 적용할지 정의. around, Before, After, after-returning, after-throwing
  • Jointpoint: Advice를 적용 가능한 지점. 메소드 호출 시점, 예외 발생 시점 등 특정 작업시 시작 되는 시점. Advice를 weaving하는 포인트를 JointPoint라고 한다
  • Weaving: Advice를 핵심 로직 코드에 적용하는 것을 위빙이라고 한다. 즉 공통 코드를 핵심 로직 코드에 삽입하는 것. Aspect를 Target 객체에 제공하여 새로운 프록시 객체를 생성하는 과정
  • Target: 핵심 로직을 구현하는 클래스
  • Proxy: 대상 객체에 Advice가 적용된 후 생성된 객체


1-4. 스프링에서의 AOP 구현 방법: proxy를 이용한다

  • 호출부(client) –> 대행(proxy) –> 핵심기능(target)


1-5. 스프링에서 AOP 구현 방법

  • XML 스키마 기반의 AOP 구현
  • @Aspect 어노테이션 기반의 AOP 구현



2. XML 기반의 AOP 구현

2-1. 작업 순서

  • 1) 의존 설정(pom.xml)

  • 2) 공통 기능의 클래스 제작 - Advice 역할 클래스

public class LogAop {
  public Object loggerAop(ProceedingJointPoint jointPoint) throew Throwable {
    String signatureStr = jointPoint.getSignature().toShortString();
    System.out.println(signatureStr + " is start");
    long st = System.currentTimeMills();

    try {
      Object obj = jointPoint.proceed(); // 핵심 기능 코드 실행
      return obj;
    } finally {
      long et = System.currentTimeMills();
      System.out.println(signatureStr + " is finished");
      System.out.println(signatureStr + " 경과시간 : " + (et-st) );
    }
  }
}


  • 3) XML 설정 파일에 Aspect 설정
<!-- com.test.* 내부의 클래스 메소드 호출 시 around aspect 실행 됨 -->
<bean id="logAop" class="com.test.yjh.LogAop"/>

<aop:config>
  <aop:aspect id="logger" reg="logAop">
    <aop:pointcut id="publicM" expression="within(com.test.yjh.*)"/>
    <aop:around pointcut-ref="publicM" method="loggerAop"/>
  </aop:aspect>
</aop:config>


2-2. Advice 종류

  • <aop:before>: 메소드 실행 전에 Advice 실행
  • <aop:after-returning>: 정상적으로 메소드 실행 후에 Advice 실행
  • <aop:after-throwing>: 메소드 실행 중 exception 발생 시 Advice 실행
  • <aop:after>: 메소드 실행 중 exception이 발생하여도 advice 실행
  • <aop:around>: 메소드 실행 전/후 및 exception 발생 시 advice 실행



3. @Aspect를 이용한 AOP구현

3-1. 작업 순서

  • 1) 의존 설정(pom.xml)
  • 2) @Aspect 어노테이션을 이용한 Aspect 클래스 제작
  • 3) XML파일에 <aop:aspectj-autoproxy/> 설정
@Aspect
public class LogApp {

  @Pointcut("within(com.test.yjh.*)")
  private void pointcutMethod(){

  }

  // 방법1) point cut 사용
  @Around("pointcutMethod())
  public Object loggerAop(ProceedingJoinPoint joinPoint) throws Throwable {
    String signatureStr = jointPoint.getSignature().toShortString();
    System.out.println(signatureStr + " is start");
    long st = System.currentTimeMills();

    try {
      Object obj = jointPoint.proceed(); // 핵심 기능 코드 실행
      return obj;
    } finally {
      long et = System.currentTimeMills();
      System.out.println(signatureStr + " is finished");
      System.out.println(signatureStr + " 경과시간 : " + (et-st) );
    }
  }

  // 방법2) expression 적용
  @Before("within(com.test.yjh.*)")
  public void beforeAdvice(){
    System.out.println("beforeAdvice")
  }
}



4. Aspect Pointcut 표현식

  • pointcut을 지정할 때 사용하는 표현식으로 AspectJ 문법을 사용한다
  • * : 모든 / . : 현재 / .. : 0개 이상
  • Execution
// public void인 모든 get메소드
@Pointcut("execution(public void get*(..))")

// com.test.yjh 패키지에 파라미터가 없는 모든 메소드
@Pointcut("execution(* com.test.yjh.*.*()))

// com.test.yjh 패키지 & com.test.yjh 하위 패키지에 파라미터가 없는 모든 메소드
@Pointcut("execution(* com.test.yjh..*.*()))

// com.test.yjh.Book 안의 모든 메소드
@Pointcut("execution(* com.test.yjh.Book.*()))

  • within
@Pointcut("within(com.test.yjh.*)") // com.test.yjh 패키지 안에 있는 모든 메소드
@Pointcut("within(com.test.yjh..*)") // com.test.yjh 패키지 및 하위 패키지 안에 있는 모든 메소드
@Pointcut("within(com.test.yjh.Book)") // com.test.yjh.Book의 모든 메소드

참고

인프런-신입프로그래머를 위한 자바스프링프레임워크 강좌