[java spring]spring AOP 구현(Annotation 방법) :: 개발/일상_Mr.lee

[java spring]spring AOP 구현(Annotation 방법)

Posted by Mr.mandu.
2016. 4. 16. 21:03 개발/java,spring


이번에는 Annotaion 방법을 이용하여 Spring AOP를 구현해보겠습니다.

xml방법에서  transaction-context.xml 을 설정 했듯이 

Annotaion 방식도  transaction-context.xml을 설정해야 합니다.

우선 기존에 xml 방식으로 구현 하셨던 분은 aop 설정 선언문을 주석 처리 합니다.


그리고 @Aspect 어노테이션을 통해서 bean을 등록 시켜주게 하기위해 

 

를 설정합니다.


그리고 AOP를 수행하는 클래스를 만들겠습니다. 

저는 AnnotationAopTest.java로 만들었습니다.





이어서 테스트 했던 소스를 첨부하겠습니다.

package lee.test.spring.aop; 

import java.util.Arrays;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Service;
 
@Service 
@Aspect
public class AnnotationAopTest {

	@Pointcut("execution(* lee..*Impl.*(..))")
    public void annotationAOP() {
		 //@Pointcut("within(test..*)")
		//@Pointcut("within(test.spring.aop..*)")
		//@Pointcut("bean(customerService)")
    }

   @Before("annotationAOP()")
   public void before(JoinPoint joinPoint){
	   System.out.println("----------------------Annotation-----------beforeAOP");
   }
   @After("annotationAOP()")
   public void after(){
	   System.out.println("----------------------Annotation-----------afterAOP");
   }
  @AfterReturning(pointcut="annotationAOP()",  returning="retValue")
  public void afterReturningAOP(JoinPoint joinPoint, Object retValue){
	   System.out.println("---------------Annotation--------------afterReturningAOP");
	
   }
	@Around("annotationAOP()")
    public Object measure(ProceedingJoinPoint joinPoint) throws Throwable {
    	 long start = System.nanoTime(); //현재의 나노시간을 반환
    	  try {
    		  System.out.println("---------------Annotation--------------AroundAOP");
    	   Object result = joinPoint.proceed(); // 대상객체의 메서드 실행(ProceedingJoinPoint 타입은 대상 객체의 메서드를 호출할 때 사용)
    	   return result;
    	  } finally {
    		  System.out.println("---------------Annotation--------------AroundAOP");
    	   long finish = System.nanoTime();
    	   Signature sig = joinPoint.getSignature(); //메서드의 시그니쳐
    	   System.out.printf("%s.%s(%s) 실행 시간 : %d ns\n",
    	     joinPoint.getTarget().getClass().getSimpleName(),
    	     sig.getName(), 
    	     Arrays.toString(joinPoint.getArgs()), //인자목록을 반환
    	     (finish - start));
    	  }
    }
	 
	@AfterThrowing(pointcut="annotationAOP()", throwing="ex") //예외값 지정
    public void after_throwing(Throwable ex){
		System.out.println("---------------Annotation--------------AfterThrowing");
    }
     
} 

설명해보면

@Aspect를 선언하여 해당 클래스를 AOP클래스로 사용하겠다는 의미 입니다.

@Service는 해당 객체를 bean으로 등록하기위해 선언하였습니다.


Annotation에서의 Pointcut 설정을 먼저 보실수 있는데요

빈 함수에 pointcut의 어노테이션을 선언하고 범위를 지정합니다. 

Pointcut의 또다른 선언 방법으로 아래의 주석을 보시면 within과 bean으로 Pointcut을 설정한 화면을 보실 수 있습니다.


within의 방식은 해당 패키지의 클래스에 포함된 메소드를 통째로 선택 하겠다는 의미입니다.

bean 방식은 말그대로 bean을 선택하겠다는 의미 입니다.


그 이후에는 Before, After AfterReturning 을 선언한 화면을 보실 수 있습니다.

그리고 Around에서 로직의 실행시간을 나노시간으로 출렸하였는데요. 10억분의1초라는 뜻입니다.

즉, 1,000,000,000 나노 시간 = 1초 라는 뜻입니다.


xml로 AOP를 구현 하셨다면 손 쉽게 Annotation 방식으로도 구현 하셨을 거라고 믿습니다.

저는 처음에  컨트롤러에서 컴포넌트 스캔을 해줬기 때문에 더이상 이 문구는 쓸 필요가 없다고 생각해서 써주지 않았습니다.

<context:component-scan base-package="lee">

<context:include-filter type="annotation" expression="org.springframework.stereotype.Service"/>

<context:include-filter type="annotation" expression="org.springframework.stereotype.Repository"/>

       <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>

</context:component-scan>

이렇게 써줘야 빈으로 등록 되고 AOP를 실행 시킬수 있다는 점을 잊지마세요