AOP

James_·2022년 5월 16일
0

AOP(Aspect Oriented Programming)?

관점지향 프로그램
스프링 어플리케이션은 대부분 특별한 경우를 제외하고는 보통 MVC 웹 어플리케이션 WebLayer,Buisness Layer, Data Layer로 정의된다.

WebLayer

  • RestAPI를 제공하며 Client중심의 로직 적용

BuisnessLayer

  • 내부 정책에 따른 Logic을 개발하며, 주로 해당 부분을 개발

DataLayer

  • 데이터베이스 및 외부와의 연동을 처리

주요 Annotation

  • Aspect: AOP를 정의하는 클래스에 할당
  • Poincut 기능을 어디에 적용시킬지, 메소드,어노테이션 등 AOP를 적용 시킬 지점을 설정
  • Before: 메소드를 실행하기 이전
  • After: 메소드가 실행한 후(예외발생도 포함)
  • AfterReturning: 메소드가 성공적으로 실행 시(No throws)
  • AfterThrowing: 메소드 호출 실패시 예외 발생(Throws)
  • Around: Before/After 모두 제어

AOP 적용해보기(1)

우선 AOP를 적용하기 위해 컨트롤러를 만들어준다. 그 전에 controller 패키지 폴더를 만드는 것을 잊으면 안된다.

@RestController
@RequestMapping("/api")
public class RestApiController {

    @GetMapping("/get/{id}")
    public  String get(@PathVariable Long id, @RequestParam String name){
        System.out.println("get method");
        System.out.println("get "+ id);
        System.out.println("get method " + name);
        return id + " " + name
    }

    @PostMapping("/post")
    public User post(@RequestBody User user){
        System.out.println("post method: "+user);
        return user;
    }
}

그리고 aop패키지를 만들고 ParameterAop 클래스를 만들어준다.

@Aspect
@Component // Spring으로써 컴포넌트로 관리를 해주기 위해 컴포넌트 어노테이션 추가
public class ParameterAop {
 // 특정 패키지 하위(controller 하위)
    @Pointcut("execution(* com.ioc.ioc.controller..*.*(..))")
    private void  cut(){}

    // 위에 메소드
    @Before("cut()")
    public void before(JoinPoint joinPoint){
        Object[] args =  joinPoint.getArgs();
        for(Object obj: args){
            System.out.println("type"+obj.getClass().getSimpleName());
            System.out.println("value"+obj);
        }

    }

    @AfterReturning(value = "cut()",returning = "obj")
    public void afterReturning(JoinPoint joinPoint,Object obj){

        System.out.println("return object");
        System.out.println(obj);
    }
}

스프링 Run후 api가 호출될때마다 전 후 출력이 되는 것을 확인할 수 있다.

메소드 이름까지 출력하기

public class ParameterAop {
 	...
    // 위에 메소드
    @Before("cut()")
    public void before(JoinPoint joinPoint){
 		MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        Method method = methodSignature.getMethod();
        System.out.println(method.getName());

        }

}

AOP 적용해보기(2)

어노테이션을 이용해서 메서드들을 전체 걸린 시간을 출력하는 AOP를 만들어보겠다.
일단 annotation 패키지를 만들고 Target annotaion을 생성해준다.

@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME) // 런타임 실행시
public @interface Timer { }

aop 패키지 하위에 TimerAop 클래스를 만들어준다.

@Aspect
@Component // Aop 클래스는 bean으로 등록할 수 없고 메소드에 bean을 붙일 수 있다.
public class TimerAop {

    // 특정 패키지 하위(controller 하위)
    @Pointcut("execution(* com.ioc.ioc.controller..*.*(..))")
    private void  cut(){}

    @Pointcut("@annotation(com.ioc.ioc.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();
        // 얼마만큼 걸리는지 추가
        System.out.println("total time" + stopWatch.getTotalTimeSeconds());
    }
}

그리고 예시를 돕기 위해서 Controller API메서드를 하나 추가해준다.

@RestController
@RequestMapping("/api")
public class RestApiController {

 	...
    
    @Timer
    @DeleteMapping("/delete")
    public void delete() throws InterruptedException{
        Thread.sleep(1000 * 2); // 2초간 슬립
    }
}

실행 후 delete 메서드를 api를 통해 call해주면 total time 2.000086563
시간이 잘 뜨게된다!

profile
Android 개발자

0개의 댓글