AOP(aspect-oritented programming) 이란?
AOP는 관심사 횡단 교차점의 분리로 모듈화를 향상시키는 패러다임이다. 코드 자체를 변경하지 않고도 기존의 코드에 부가적인 행동을 추가시킬 수 있는데, 대신에 "pointcut" 설정을 통해 수정되는 코드를 별도로 지정해야 한다. 예를 들어, "함수의 이름이 set으로 시작하는 경우, 로그시간을 계산한다" 가 있다. aop를 통해 비지니스 로직에 중요하지 않은 행위들이 코드의 중요 부분을 복잡하게 만들지않고 프로그램에 추가가 가능하다.
AOP는 프로그램 로직을 개별의 부분으로 분리시킨다.(관심사의 분리라고도 한다.) 사실 거의 모든 프로그래밍 패러다임은 구현, 추상화, 관심사의 통합으로 사용될 수 있는 추상화(함수, 절차, 모듈, 클래스, 메서드) 기능을 제공함으로써 관심사가 독립적인 엔티티로 분리되도록 몇가지 방법들을 지원하다.
어노테이션이름 | 설명 |
@Aspect | aop를 정의하는 class에 할당 |
@Pointcut | 기능을 어디에 적용시킬지 메서드? 어노테이션? |
@Before | 메서드 실행하기 이전 |
@After | 메서드가 성공적으로 실행 후 예외가 발생되더라도 실행 |
@AfterRunning | 메서드 호출 성공 실행 시(not throws) |
@AfterThrowing | 메서드 호출 실패 예외 발생(throws) |
@Around Before/After | 모두 제어 |
@Aspect
@Component
public class ParameterAop {
//1
@Pointcut("* com.example.aop.controller..*.*(..))")
private void cut() {}
//2
@Before("cut()")
public void before(JoinPoint joinPoint) {
MethodSignature methodSignature = (MethodSignatrue) joinPoint.getSignature();
Method method = methodSignature.getMethod();
Object[] args = joinPoint.getArgs();
for(Object obj : args) {
System.out.println("type : " + obj.getClass.getSimpleName());
System.out.println("value : " + obj);
}
}
//3
@AfterReturning("cut()", returning = "returnObj")
public void afterReturn(JoinPoint joinPoint, Object returnobj) {
System.out.println("return obj : ");
System.out.println(returnobj);
}
}
1. @PointCut : 어디에 사용할지 정의한다. 현재, aop패키지의 controller에 있는 모든 곳에 적용된다. 즉, 해당 컨트롤러들의 어떠한 메서드가 실행되더라도 aop는 실행된다.
2. @Before : 메서드 시작 전에 어떤 행동을 할 지 정의하다. 기본적으로 JoinPoint라는 매개변수를 통해 호출되는 클래스, 메서드, 값 등을 호출 할 수 있다.
3. @AfterRunning : 메서드가 종료되고 나서 어떤 행동을 할 지 정의하다. 추가적으로 returnObj가 있는데, 메서드가 반환하는 값을 사용할 수 있다.
메서드의 실행시간을 확인할 수 있는 aop 기능으 만들어 보자
@Aspect
@Component
public class TimerAop {
//aop.controller 하위에 메서드가 실행될 때
@Pointcut("execution(* com.example.aop.controller..*..*(..))")
private void cut() {}
//Timer라는 어노테이션이 붙여져 있는 메서드가 실행될 때
@Pointcut("@annotation(com.example.aop.annotation.Timer)")
private void enableTimer() {}
@Around("cut() && enableTimer()")
public void around(ProceedingJoinPoint joinPoint) throws Throwable {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
Object result = joinPoint.proceed();
stopWatch.stop();
Syste.mout.println("total time: " + stopWatch.getOtalTimeSeconds());
}
}
aop는 먼저 @Aspect와 @Component를 class에 붙여주어야 한다. Aop를 사용하겠다는 의미와, Spring에서 Bean으로 관리하겠다고 선언하는 것이다.
관련 코드를 짤 때 @Pointcut을 머저 작성하며, 몸통 구현부는 비워둔다. 어디에 적용하고 싶은지 정의한다. 특히 enableTimer의 경우 @annotation에 설정한 것으로 다음의 Timer 인터페이스를 생성해야 한다.
@Target((ElementType.TYPE, ElementType.METHOD))
@Retention(RetentionPolicy.RUNTIME)
public @interface Timer {
}
TYPE과 METHOD에 적용할 수 있는 @Timer 어노테이션으로 만들어주며, Runtime동안 작동하는 어노테이션이다.
@Around는 실제적으로 기존 코드에 추가되는 부분이다. @Around("cut() && enableTimer()") 는 && 때문에 2가지 조건이 모두 만족되어야 함을 의미한다. 즉, aop.controller 하위에 있으면서도, @Timer 어노테이션이 있어야 한다. StopWatch 크래스를 이용해 해당 메서드 실행이 얼마나 걸리는지 계산할 수 있다. 만약 기준 시간을 초과하면 적절한 메세지를 리턴하도록 할 수 있다.
'학습 > Java' 카테고리의 다른 글
Validation 어노테이션 직접 만들어보기 (0) | 2021.08.12 |
---|---|
@Qualifier & @Resource & @Autowired (0) | 2021.08.12 |
Spring MVC (0) | 2021.08.08 |
IoC, DI (0) | 2021.08.08 |
ObjectMapper (0) | 2021.08.06 |