본문 바로가기

JAVA/Spring

Spring AOP

반응형

AOP(Aspect Oriented Programming)

기존의 비즈니스 로직외 작성해야 하는 코드를 별도로 분리함으로써 개발자가 좀 더 비즈니스 로직에만 집중해서 처리할 수 있는 방법을 제공

사전적 의미로는 "측면 혹은 어떤 도형이나 건물의 면" 의미하지만, 실제 프로그램 개발에서 의미하는 것은 '비즈니스 로직은 아니지만 반드시 해야하는 작업'


공통적이고 반복적인, 그러나 비즈니스 로직의 핵심이 아닌 부분을 처리할때...

횡단 관심사(cross-concern)는 시스템의 여기저기에서 공통으로 사용되지만, 그 자체가 목적이 아닌 오히려 시스템의 완성도를 높여주는 역할로 보안처리나 로그, 이중백업등 사용

"개발의 핵심적인 비즈니스로직을 개발하는데만 집중하고 나머지 부가적인 기능은 설정을 통해 조정하라"


프록시(Proxy) 패턴방식으로 구현

외부에서 특정한 객체(target)를 호출하면, 실제 객체를 감싸고 있는 바깥쪽 객체(Proxy)를 통해서 호출이 전달된다. Proxy 객체는 AOP의 기능이 적용된 상태에서 호출을 받아 사용되고, 실제 객체와 동일한 타입을 자동으로 생성할 수 있기 때문에 외부에서는 실제 객체와 동일한 타입으로 호출할 수 있다.


AOP 용어

용어

설명 

 Aspect

 공통관심사에 대한 추상적인 명칭, 예를들어 로깅이나 보안, 트랜젝션과 같은 기능 자체에 대한 용어

 Advice

 실제로 기능을 구현하는 객체

 Join points

 공통관심사를 적용할수 있는 대상 Spring AOP에서는 각 객체의 메소드가 이에 해당

 Pointcuts

 여러 메소드 중 실제 Advice가 적용되는 메소드

 target

 대상 메소드를 가지는 객체

 Proxy

 Advice가 적용되었을 때 만들어지는 객체

 Introduction

 target에 없는 새로운 메소드나 인스턴스 변수를 추가하는 기능

 Weaving

 Advice와 target이 결합되어서프록시 객체를 만드는 과정



Proxy는 일반적인 의미에서는 직접 호출하는 방식이  아니라 간전접인 호출을 하는 것을 의미한다.

원래 객체인 target을 호출할 때 외부에서 직접 target을 호출하는 것이 아니라 Advice가 적용된 Proxy 객체를 통해서 호출한다는 의미



Advice의 종류

 타입

기능 

 Before Advice

 target의 메소드 호출전에 적용

 After Advice

 target의 메소드 호출 이후에 적용

 After throwing 

 target의 예외 발생후 적용

 After

 target의 메소드 호출 후 예외의 발생에 관계없이 적용

 Around

 target의 메소드 호출 이전과 이후 모두 적용(가장 광범위하게 사용됨)


Spring 1.x에서는 AOP 기능을 적용하기 위해서 별도의 Proxy 객체를 만드는 설정을 추가해야하는 불편함

Spring 2.x이후 이러한 설정이 애노테이션 방식으로 가능

AOP를 적용하는 방식 역시 XML이나 애노테이션을 있다


XML 경우 

root-context.xml

<aop:aspectj-autoproxy></aop:aspectj-autoproxy> Proxy 객체 생성을위해 설정

<aop:config></aop:config> AOP기능을 설정


예)

@Component

@Aspect

public class SampleAdvice {

private static final Logger logger = LoggerFactory.getLogger(SampleAdvice.class);


@Before("execution(* org.zerock.service.MessageService*.*(..))")

public void startLog() {

logger.info("-----------------------");

logger.info("-----------------------");

}

}

설명)

클래스 선언부의 @Aspect 애노테이션은 AOP 기능을 하는 클래스의 선언에 추가해줘야한다.

@Component는 스프링의 빈으로 인식되기 위해 설정함

startLog() 설정중 @Before는 해당 메소드를 먼저 실행한 후 target 메소드가 실행되게 하는 것

execution으로 시작하는 구문은 Poincut을 지정하는 문법으로 AspectJ 언어의 문법을 사용한다.

org.zerock.service.MessageService 로 시작하는 모든 클래스의 *(모든) 메소드를 지정하고 있다


실행시 전달되는 파리미터 (JointPoint 기능)

 주요 메소드

설명 

 Object[] getArgs()

 전달되는 모든 파라미터들을 Object의 배열로 가져온다

 String getKind()

 해당 Advice의 타입을 알아낸다.

 Signature getSignature()

 실행하는 대상 객체의 메소드에 대한 정보를 알아낼 때 사용

 Object getTarget()

 target 객체를 알아낼때 사용

 Object getThis()

 Advice를 행하는 객체를 알아낼 때 사용

예)

  public startLog(JoinPoint jp) {

logger.info("-----------------------");

logger.info("-----------------------");

logger.info(Arrays.toString(jp.getArg()));

}

설명)

전달되는 파라미터들을 확인할 수 있다.



Advice의 종류에서 가장 강력하게 사용할 수 있는 것은 Around 타입의 Advice이다

Around 타입은 다른 종류와 달리 메소드 실행에 직접 관여한다.

Object proceed() 다음 Advice를 실행하거나 실제 target 객체의 메소드를 실행하는 기능

ProceedingJoinPoint는 바로 앞의 JointPoint의 하위 인터페이스 이다

따라서 JoinPoint의 모든 메소드를 가지면서도 직접 target 객체의 메소드를 실행할 수 있는 기능이 추가된 형태


예)

@Around("execution(* org.zerock.service.Message*.*(..))")

 public Object timeLog(ProceedingJointPoint pjp) throws Throwable {

long startTime = System.currentTimeMillis();

logger.info(Array.toString(pjp.getArgs()));

Object result = pjp.proceed();

long endTime = System.currentTimeMillis();

logger.info(pjp.getSignaure().getName() + " : "+ (endTime - startTime) );

return result;

 }

설명)

메소드의 선언에는 일반적인 Exception이 아닌 상위 타입의  Throwable이 사용

Object result = pjp.proceed();

proceed()를 이용해서 실제 메소드를 호출한다.

@Around를 이용하는 경우 반드시 메소드의 리턴타입은  Object로 선언해야한다.

다른 Advice와 달리 @Around 메소드를 직접호출하고 결과를 반환해야만 정상적인 처리가 된다.

수정사항을 반영한 뒤에 다시 호출하게 되면 메소드의 실행의 전후로 Advice가 적용된다.




반응형

'JAVA > Spring' 카테고리의 다른 글

Spring Interceptor  (0) 2017.12.13
Spring Transaction  (0) 2017.11.27
RestController  (0) 2017.11.20
예외처리 기본  (0) 2017.11.20
모델2방식과 스프링 MVC  (0) 2017.11.20