티스토리 뷰

생활코딩/Spring

스프링 배우기 - AOP

우봉이 2014. 3. 18. 15:49

AOP란?

Aspect Oriented Programming : 관점 지향 프로그래밍 을 의미한다.

특정 기능이 있는 클래스 안에는 본질적인(핵심적인) 처리만 기술을 하고, 본질적이지 않은(추가 기능, 부가 기능) 을 따로 기술을 하는 기술이다.

구체적으로는 로그 출력이나, 예외 처리 등 공통화할 수 있는 처리를 Aspect라는 하나의 단위로 모아서 어떤 객체가 원래 해야 할 일만 기술할 수 있도록 만드는 기술이다.

AOP 개념에 대한 내용은 이 분의 글을 보길 바란다. 정리가 매우 잘 되어 있다. - http://isstory83.tistory.com/90 

AOP는 XML에 등록하는 방법과 AOP 소스 코드에 애노테이션을 이용하는 방법 두 가지가 있다.

servlet-context.xml 파일에 <aop:aspectj-autoproxy/> 코드를 작성한다.

여기서 xsd xmlns:aop="http://www.springframework.org/schema/aop" 이 내용이 필요하다.

스프링에 경우 namespace tab에서 체크 박스를 클릭하면 된다.

이제, AOP에 필요한 라이브러릴 추가 해야 한다. ( mvnrepository.com 참조 )

  1. aopalliance-1.0.jar

  2. aspectjrt-1.6.9.jar

  3. aspectjweaver-1.7.4.jar

  4. com.springsource.net.sf.cglib-2.2.2.jar

1,2 번은 보통 기본 스프링 프로젝트에 내장되어있고, 3,4 번을 찾아서 추가하면 된다.

※ cglib 3.x 버전 넣으면 에러 난다. 아직 호환이 안됨


먼저, AOP를 소스코드에 애노테이션을 이용한 방법을 보자!

테스트를 위한 컨트롤러를 대충 구현하자.

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class AspectTestController {

	ModelAndView mav = new ModelAndView();

	@RequestMapping("/test_before.do")
	public ModelAndView test_Before() {

		System.out.println("2.Before 어드바이스 수정 후에 출력");
		mav.setViewName("home");
		return mav;
	}

	@RequestMapping("/test_after.do")
	public ModelAndView test_After() {

		System.out.println("3.After 어드바이스 수행 후에 출력");
		mav.setViewName("home");
		return mav;
	}

	@RequestMapping("/test_method.do")
	public ModelAndView test_Around() {
		for (int i = 1; i < 5000000; i++) {
			i = i + 1;
		}
		mav.setViewName("home");
		return mav;
	}
}

다음은, AOP를 구현한 소스 파일이다. 이 파일을 작성하고 Servlet-context.xml에 빈 등록을 해주면 된다.

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;

@Aspect
public class Test_AspectJ {

	@Pointcut("execution(* com.ktds.aop.AspectTestController.*Before())")
	public void human() {
	}

	@Pointcut("execution(* com.ktds.aop.AspectTestController.*After())")
	public void human1() {
	}

	@Pointcut("execution(* com.ktds.aop.AspectTestController.*Around())")
	public void human2() {
	}

	@Before("human()")
	public void before_test() {
		System.out.println("1. @Before어드바이스에서 출력");
	}

	@After("human1()")
	public void after_test() {
		System.out.println("4. @After어드바이스에서 출력");

	}

	@Around("human2()")
	public Object test_Method(ProceedingJoinPoint joinPoint) throws Throwable {
		String signature = joinPoint.getSignature().toString();
		System.out.println(signature + " 시작");
		long start_time = System.currentTimeMillis();
		try {
			Object result = joinPoint.proceed();
			return result;
		} finally {
			long end_time = System.currentTimeMillis();
			System.out.println(signature + " 종료");
			System.out.println(signature + " 실행시간" + (end_time - start_time)+ "ms");
		}
	}
}

Pointcut 에 어떤 메소드에 적용 될지 위치를 지정하고, 메소드 이름으로 어드바이스의 대상으로 이용하는 방법이다.

Pointcut 의 메소드 이름은 의미 있게 작성하면 되고, 어드바이스 애노테이션의 값으로 사용한다. 

이렇게 구현하면, Pointcut 으로 등록된 메소드가 호출 될 때 해당 어드바이스의 내용이 수행된다.

컨트롤러의 맵핑 된 url 로 접속하면 아래와 같이 결과를 얻을 수 있다.

1. @Before어드바이스에서 출력

2.Before 어드바이스 수정 후에 출력

3.After 어드바이스 수행 후에 출력

4. @After어드바이스에서 출력

ModelAndView com.ktds.aop.AspectTestController.test_Around() 시작

ModelAndView com.ktds.aop.AspectTestController.test_Around() 종료

ModelAndView com.ktds.aop.AspectTestController.test_Around() 실행시간 4ms


댓글