AOP란?
Aspect Oriented Programming의 약자로, 관점지향 프로그래밍이라고 불린다. 여러 객체에 공통으로 적용할 수 있는 기능을 구분함으로써 재사용을 높여주는 프로그래밍 기법이다. AOP는 핵심 기능과 공통 기능의 구현을 분리함으로써 핵심 기능을 구현한 코드의 수정 없이 공통 기능을 적용할 수 있게 만들어준다.
다시 말해 핵심 기능의 코드를 수정하지 않으면서 공통 기능의 구현을 추가하는 것이 AOP이다.
* 횡단관심 : 로깅, 보안, 트랜젝션 등 다수의 모듈에서 반복적으로 나타나는 부분
예를 들어 C사는 JSON 규격으로 통신을 하는데, A사와 B사는 UTF-8규격을 맞추지 못한다고 가정해보자.
이럴경우 A사와 B사에 C사의 코드를 그대로 적용하면 한글이 깨져서 나올것이다.
이를 해결하기 위해 A사와 B사를 대상으로 if문을 설정할 수도 있고, 최소한의 객체지향을 만들어 A사와 B사를 위한 Class를 만들수도 있다. 하지만 이 과정에서도 반복적인 프로그래밍이 수반되기 마련이다. AOP는 여기서 반복된 로직이나 메소드 을 한곳으로 몰아서 코딩을 할 수 있게 해준다.
AOP과련 주요 Annotation
Annotation | 의미 |
@Aspect | 자바에서 널리 사용하는 AOP 프레임워크에 포함되며, AOP를 정의하는 Class에 할당 |
@Pointcut | 기능을 어디에 적용시킬지, 다시말해 메소드, Annotion 등 AOP를 적용시킬 지점을 설정 |
@Before | 메소드를 실행하기 이전 |
@After | 메소드가 성공적으로 실행 된 후, 예외가 발생되더라도 실행 |
@AfterReturning | 메소드 호출 성공 실행 시 (Not Throws) |
@AfterThrowing | 메소드 호출 실패 예외 발생 (Throws) |
@Around | Before / After 모두 제어 |
AOP 예제
아래 예제코드들을 활용하여 AOP를 구축한다.
ParameterAop를 통해 구축된 AOP를 통해 POST, GET 메소드 등을 이용할 때 어떠한 값이 들어갔고 어떠한 값이 리턴됐는지를 볼수있다.
[RestApiController.java]
@RestController
@RequestMapping("/api")
public class RestApiController {
@GetMapping("/get/{id}")
public String get(@PathVariable Long id, @RequestParam String name){
return id + " " + name;
}
}
참고로 해당 파일은 con.example.aop 패키지 내부의 controller에 위치해있다.
[ParameterAop.java]
@Aspect
@Component
public class ParameterAop {
// AOP를 통해서 POST, GET메소드 등을 이용할 때 어떠한 값이 들어갔고 어떠한 값이 리턴됐는지를 볼 수 있다.
//pointcut : 어느 부분에 적용할지를 결정
@Pointcut("execution(* com.example.aop.controller..*.*(..))") // controller하위에 있는 모든 리소스를 aop로 보겠다
private void cut(){}
@Before("cut()") // 위에 cut()이 실행되는 시점에 before메소드를 실행하겠다.
public void before(JoinPoint joinPoint){
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature(); // 정확히 어떤 메소드가 실행됐는지 알려준다.
Method method = methodSignature.getMethod();
System.out.println(method.getName());
Object[] args = joinPoint.getArgs();
for(Object obj : args){
System.out.println("type : " +obj.getClass().getSimpleName());
System.out.println("value :" + obj);
}
}
@AfterReturning(value="cut()", returning = "returnObj") // 위에 cut이 정상 실행되고 난 뒤의 반환값을 알고 싶다.
public void afterReturn(JoinPoint jointPoint, Object returnObj){
System.out.println("return obj");
System.out.println(returnObj);
}
}
참고로 afterReturn의 매개변수들은 @AfterReturning의 매개변수와 동일하다.
위 코드가 실행되는 순서를 단계적으로 보면 다음과 같다.
순서 | 실행 메소드 |
1 | cut() -> cut() 메소드를 보면 Pointcut을 이용해 해당 AOP를 어디에 적용할지가 나와있다. RestApiController는 aop.controller 내부에 위치해있으므로, RestApiController가 AOP를 적용하는 지점이 된다. |
2 | Before() -> 이 메소드는 cut()으로 지정한 AOP적용 지점이 실행되기 이전에 실행된다. |
3 | cut()으로 지정된 AOP 적용지점 -> 여기서는 RestApiController의 get이 실행된다 |
4 | AfterReturning() -> get()메소드가 끝나고 실행된다. |
AOP의 효과
위 코드에 AOP를 적용하지 않았다고 가정해보자.
그렇다면 get이나 post메소드 내부에 system.out.println을 적어서 매번 log를 찍어내야 할 것이다.
설령 별도의 클래스를 만들어 정보를 출력해내는 class를 만들어 적용한다 하더라도, get이나 post내부에는 해당 클래스를 호출하는 코드를 적어내야하며, 만약 어떤 메소드들에는 해당 클래스가 적용되지 않고 또 다른 메소드들에는 해당 클레스에 특별한 기능이 더해져야 한다면 일일이 if - else를 적어 코드가 난잡해질수 있다.
이렇게 AOP는 핵심 기능과 공통 기능의 구현을 분리함으로써, 핵심 기능을 구현한 코드의 수정 없이 공통 기능을 적용할 수 있게 만들어준다.
참고 사이트
AOP개념 설명 : https://ktko.tistory.com/entry/Spring-AOP-개념-설명
'👩🏻💻 Programming > SpringBoot' 카테고리의 다른 글
Spring Boot와 Validation (1) (0) | 2021.08.11 |
---|---|
Bean vs Component (0) | 2021.08.10 |
IoC(제어의 역전)와 DI(의존성 주입) (0) | 2021.08.08 |
SpringBoot의 Object Mapper (0) | 2021.08.05 |
GET과 Query Parameter, POST와 Databody (0) | 2021.08.03 |