개발 등/SPRING

[펌글] @Aspect Annotation을 이용한 AOP

darkhorizon 2009. 4. 2. 20:50
728x90
반응형

이번엔 @Aspect Annotation을 이용해서 AOP를 설정해보도록 하자....

이것 역시 XML 스키마를 이용하여 설정한다..

 

<beans ...

    xmlns:aop=http://www.springframework.org/schema/aop ... >

 

일단 xmlns에 aop를 추가해주고...

 

<aop:aspectj-autoproxy/>

 

위 태그를 사용하면 @Aspect Annotation이 사용된 클래스의 Advice 및 Pointcut을 알맞은 빈 객체에 적용한다...

실제 @Aspect Annotation을 사용한 클래스를 살펴보자..

 

package test.aspect.annotation

 

import org.aspectj.lang.JoinPoint;

import org.aspectj.lang.annotation.After;

import org.aspectj.lang.annotation.AfterReturning;

import org.aspectj.lang.annotation.AfterThrowing;

import org.aspectj.lang.annotation.Aspect;

import org.aspectj.lang.annotation.Before;

 

@Aspect

public class TestAspect

{

    @Before("execution(public * test.aspect.*.*(..))")

    public void Before(JoinPoint joinPoint)

    {

        System.out.println("Before");

    }

 

    @AfterReturning(pointcut = "execution(public * test.aspect.*.*(..))" returning = "ret")

    public void AfterReturning(JoinPoint joinPoint, Object ret)

    {

        System.out.println("AfterReturning");

    }

 

    @AfterThrowing(pointcut = "execution(public * test.aspect.*.*(..))" throwing = "ex")

    public void AfterThrowing(JoinPoint joinPoint, Throwable ex)

    {

        System.out.println("AfterThrowing");

    }

 

    @After("execution(public * test.aspect.*.*(..))")

    public void After(JoinPoint joinPoint)

    {

        System.out.println("After");

    }

 

    @Around("execution(public * test.aspect.*.*(..))")

    public void before(ProceedingJoinPoint joinPoint joinPoint)

    {

        System.out.println("Around");

        Object ret = joinPoint.proceed();

    }

}

 

앞서 살펴보았던 POJO를 이용한 설정과 매우 유사하다..

단지 소스 코드에 직접 입력하느냐 설정 파일에 설정하느냐의 차이만 있을 뿐이다...

위의 TestAspect를 생성해주면 test.aspect 패키지의 모든 클래스의 모든 메소드에 AOP가 적용이 된다..

 

<bean class="test.aspect.annotation.TestAspect"/>

<bean id="test" class="test.aspect.TestService"/>

 

위의 예제는 test.aspect.TestService의 모든 메소드에 TestAspect가 적용되는 설정이다...

그렇다면 도대체 AspectJ의 Pointcut 표현식이 어떤 뜻인지 궁금해진다..

 

Spring에서 제공하는 AspectJ의 Pointcut 명시자는 execution과 within 그리고 bean 명시자이다..

먼저 Advice를 적용할 메소드를 명시할 때 사용하는 execution부터 살펴보도록 하자..

 

execution([접근명시자패턴] 리턴타입패턴 이름패턴(파라미터패턴))

 

접근명시자패턴은 public, protected, private 등을 사용할 수가 있고 생략 가능하다..

리턴타입패턴은 가능한 모든 리턴 타입을 사용할 수 있고..

이름패턴에는 패키지를 포함한 클래스 이름과 메소드 이름을 사용하고...

파라미터패턴에는 매칭될 파라미터에 대해 명시해준다...

또한 모든 패턴에는 * 를 이용하여 모든 값을 명시할 수 있고 ..을 이용하여 0개 이상이라는 의미를 표현할 수 있다..

예제를 살펴보자....

 

execution(public void set*(..)) : 리턴 타입이 void이고 set으로 시작하는 파라미터 0개 이상인 public 메소드

execution(* test.aspect.*.*()) : test.aspect 패키지의 파라미터가 없는 모든 메소드

execution(* test.aspect..*.*(..)) : test.aspect 패키지 및 하위 패키지에 파라미터가 0개 이상인 메소드

execution(void test.aspect.TestService.test()) : 리턴 타입이 void인 TestService의 test 메소드 호출

execution(* test*(*)) : test로 시작하는 파라미터 1개를 갖는 메소드

execution(* test*(*, *)) : test로 시작하는 파라미터 2개를 갖는 메소드

execution(* test*(Integer, ..)) : test로 시작하고 첫번째 파라미터는 Integer이고 1개 이상의 파라미터를 갖는 메소드

 

자세한 내용은 첨부로 올리는 AspectJ Syntax를 참고하도록 하자..

 

within 명시자는 특정 메소드가 아닌 특정 타입에 속하는 메소드를 명시할 때 사용한다...

 

within(test.aspect.TestService) : TestService의 모든 메소드

within(test.aspect.*) : test.aspect 패키지의 모든 메소드

within(test.aspect..*) : test.aspect 패키지 및 하위 패키지의 모든 메소드

 

bean 명시자는 빈의 이름을 이용하여 Pointcut을 정의한다.

 

bean(test) : 이름이 test인 빈의 메소드

bean(*test) : 이름이 test로 끝나는 빈의 메소드

 

이상 Spring에서 제공하는 AspectJ 표현식을 알아보았다..

위의 각각의 표현식은 다음과 같이 &&와 ||를 이용하여 연결할 수 있다..

 

@After("execution(public * get*()) ||execution(public * set*(..))")

 

이상으로 Spring의 AOP에 대하여 알아보았다..

아무리 봐도 제일 만만한게 Spring API를 사용하는게 아닌가 싶다..

728x90