AOP 개발 방법

본 장에서는 ProStudio에서 AOP(aspect oriented programming)의 aspect code를 작성하는 방법에 대하여 설명한다.

1. 개요

ProStudio에서 aspectj code를 작성을 위해 다음의 과정이 필요하다.

2. 환경설정

본 절에서는 aspectj code를 작성하기 위해 필요한 준비사항에 대해서 설명한다.

ProStudio에서 aspectj code를 작성하기 위해서는 ajdt(aspectj development tool) 플러그인이 설치되어 있어야 한다. 만약 ProStudio에 ajdt 플러그인 설치되어 있지 않은 경우 ajdt가 설치된 ProStudio를 받아서 진행해야 한다.

Project를 선택한 후 컨텍스트 메뉴에서 [Configure] > [Convert to AspectJ Project] 메뉴를 실행해서 aop code를 컴파일할 수 있는 프로젝트로 변경한다.

figure aop configure aspectj
Convert to AspectJ Project

이후에 다시 일반 java 컴파일러를 사용하는 프로젝트로 변경하려면 Project를 선택한 후 컨텍스트 메뉴에서 [Configure] > [Remove AspectJ Capability] 메뉴를 실행해서 일반 java 컴파일러를 사용하는 프로젝트로 변경한다.

figure aop remove aspectj
Remove AspectJ Capability

3. aspect code 작성

aspect code 작성을 위한 준비가 완료된 후엔 aspect code를 작성하는 방법, aspect code가 적용되는 target code를 작성한다. 본 절에서는 간단한 aspect 예제 코드를 통해 aop의 개념에 대해 설명한다.

다음은 aspect code를 작성하기 위해서 알아야 하는 AOP 용어들에 대한 정의이다.

용어 설명

Base code

aspect가 적용되지 않은 소스 코드로 aop 기능을 사용하지 않고 개발되는 모든 java 소스 코드이다.

Aspect code

base code에 적용될 코드이며 pointcut, advice를 포함한다.

Pointcut

base code에 aspect code가 적용되는 조건이다. 예를 들어 '특정 패키지에 속하는 클래스', '특정 method 호출' 등이 된다.

Advice

특정 pointcut 조건이 만족되었을 때 실제 실행되는 코드들이며 실행 시점 정보까지 포함한다.

aspect code 예제

다음은 모든 BO에서 add method를 호출하기 전에 호출하는 객체가 List인지 확인 후에 size check하는 로직을 수행하는 aspect code 예제이다.

  1. Aspect code 생성

    일반 java class를 생성한 후에 aspect code를 작성한다.

    figure aop generate class
    일반 java class 생성

    일반 java class에 @Aspect annotation을 붙여서 aspect code를 만든다.

    import java.util.List;
    import org.aspectj.lang.JoinPoint;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Before;
    import org.aspectj.lang.annotation.Pointcut;
    
    @Aspect
    public class SampleAspect {
  2. Pointcut 작성

    @Pointcut("within(com.tmax.proobject.model.business.BusinessObject+)")
    public void BO() {
    
    }
    
    @Pointcut("call(* add*(..))")
    public void add() {
    
    }

    첫 번째 pointcut은 BusinessObject의 구현체 클래스만 대상으로 하는 조건이고, 두 번째 pointcut은 add method를 호출하는 모든 클래스를 대상으로 하는 조건이다. pointcut을 작성하는 구체적인 방법 및 다른 pointcut을 사용하고자 한다면 AspectJ 프로그래밍 가이드를 참고한다.

  3. Advice 작성

    Advice에는 method annotation으로 실행 위치를 표시한다. @Before, @Around, @After 등…​ 이 adviec에는 before가 사용되었으므로 pointcut 대상 조건의 실행 전 advice 내부 코드를 실행하게 된다.

    @Before 내부의 value에는 pointcut을 명시한다. 이 예에서는 위에서 만든 pointcut들이 and 조건으로 연결되어 있다. 따라서 이 advice는 BusinessObject의 구현체 클래스에서 add method를 호출하기 이전에 실행된다.

    advice에 구현된 코드를 자세히 살펴보면 다음과 같다.

    @Before(value = "BO() && add()")
    public void beforeMethod(JoinPoint joinPoint) throws Exception {
        Object ret = null;
        System.out.println("before advice" + joinPoint.getTarget());
    
        if(joinPoint.getTarget() instanceof List) {
            List thisList = (List)joinPoint.getTarget();
        System.out.println("before add method, ArrayList size: " + thisList.size());
    
        if(thisList.size() > 10000)
            throw new Exception();
       }
    }

    joinPoint라는 객체에서 aop가 적용된 target 객체를 보고 이 target 객체가 java.util.List의 형태이면 target List의 size를 확인 후에 size가 10000보다 크면 exception을 낸다.

  4. target code에서 AOP 적용 확인

    만약 Aspect code가 정상적으로 작성되었다면 AOP가 적용될 대상 코드에서 확인이 가능하다.

    figure aop rulerhover1
    aspect code 예제 (1)
    figure aop rulerhover2
    aspect code 예제 (2)

aspect code가 적용되는 target code 작성 예제

다음은 com.tmax.bo 패키지에 속하는 모든 클래스들의 모든 method들 중에서 m으로 시작하는 method 호출 전, 후에 로그를 찍고 exception 처리를 하는 aspect code 예제이다.

  1. Aspect code 생성

    일반 java class에 @Aspect annotation을 붙여서 aspect code를 만든다.

    import java.util.List;
    import org.aspectj.lang.JoinPoint;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Before;
    import org.aspectj.lang.annotation.Pointcut;
    
    @Aspect
    public class SampleAspect {
  2. Pointcut 작성

    첫 번째 pointcut은 com.tmax.bo 패키지에 속하는 모든 클래스의 모든 메소드들을 대상으로 하는 조건이다.

    pointcut value에 대하여 좀더 설명하자면 다음과 같다. execution(returnType pacakge.class.methodName(arguments)) return type, class, method 등에 '*'으로 표시가 된 것은 모든 것을 대상으로 삼겠다는 것이고, argument type에서는 '..'이 모든 것을 대상으로 한다는 것을 의미한다.

    두 번째 pointcut은 이름이 'm’으로 시작하는 모든 method를 대상으로 삼는 조건이다.

    @Pointcut("execution(* com.tmax.bo.*.*(..))")
    public void anyBizOperation() {
    }
    
    @Pointcut("execution(* m*(..))")
    public void startsWithM() {
    }
  3. Advice 작성

    Around advice에서는 advice code 내부에서 실행 위치를 결정한다. 실제 target method가 실행되는 위치가 thisJoinPoint.proceed()가 호출되는 시점이다. 따라서 target method 호출 전 후로 로그를 찍을 수 있고 exception 처리도 가능하다.

    @Around(value = "anyBizOperation() && startsWithM()")
    public Object aroundMethod(ProceedingJoinPoint thisJoinPoint){
        Object ret = null;
        try{
        System.out.println("around advice before: " + thisJoinPoint.getSignature());
        ret = thisJoinPoint.proceed();
    
        System.out.println("around advice after: " + thisJoinPoint.getSignature());
        }catch(Throwable e){
            System.out.println("catch Throwble in Aspect: " + e.getMessage());
        }
      return ret;
    }
  4. target code에서 AOP 적용 확인

    figure aop rulerhover2 1
    target code에서 AOP 적용 확인 (1)
    figure aop rulerhover2 2
    target code에서 AOP 적용 확인 (2)

4. 서버 빌드과정에서 AOP 적용

본 절에서는 target code에 aspect code가 정상적으로 적용되었는지 확인하는 방법을 설명한다.

gradle script file의 ajDir로 지정된 폴더에 작성된 aspect code를 위치시키고 빌드를 한다.

figure aop gradle ext
build.gradle