일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- custom annotation
- @Header
- Thread Multiplexing
- 문자열 리터럴
- task_struct
- 문자열 불변성
- django-crontab
- rainbow table
- spring-data-jpa
- OS
- java.util.function
- Spring
- 함수형 인터페이스
- python-socketio
- Process
- Thread Library
- strict stubbing
- functional interface
- 도커
- hiberbate
- 롬복주의점
- 프로세스
- FunctionalInterface
- SystemCall
- sql-mappler
- 운영체제
- ReflectUtils
- AOP
- 쓰레드 라이브러리
- none이미지
- Today
- Total
JH's Develog
[SpringCore] AOP 본문
관점 지향 프로그래밍 - Aspect Oriented Programming
OOP로 처리하기에는 다소 까다로운 부분을 AOP라는 처리 방식을 도입하여, 특정한 함수 호출 전이나 후에 함수의 로직을 건드리지 않고 손쉽게 공통적인 처리를 수행할 수 있도록 하는 기능입니다.
주로 로깅, 트랜잭션, 인증 등 에서 자주 사용되며, AOP를 과도하게 사용할 경우 코드의 분석이 다소 어려워질 수 있음을 주의 해야합니다.
위 그림처럼 A사, B사, C사에 공통적으로 나타나는 기능을 횡단 관심(cross-cutting concern)이라고 하며, 이 부분에 AOP를 적용하여 중복을 분리하고 한 곳에서 관리할 수 있습니다.
AOP의 기본 개념 정리
용어 | 의미 |
Aspect | 횡단 관심사를 의미하며 이들을 모듈화 하는 것이 AOP이다. Aspect모듈은 Pointcut과 Advice로 구성되어있다. |
Advice | AOP에서 실제로 적용하는 기능을 뜻한다. |
Join Point | 모듈화된 특정 기능이 실행될 수 있는 포인트이다. |
Pointcut | Join Point 중에서 해당 Aspect를 적용할 대상을 뽑는 조건식이다. |
Target Object | Advice가 적용될 대상 객체이다. |
AOP Proxy | 대상 객체에 Aspect를 적용하는 경우 Advice를 덧붙이기 위해 하는 작업을 AOP Proxy라고 한다. 주로 CGLIB(Code Generation Library, 런타임에 코드를 생성하는 라이브러리) 프록시를 사용하여 프록싱 처리를 한다. |
Weaving | Advice를 비즈니스 로직 코드에 삽입하는 것을 말한다. |
Advice가 적용되는 시점을 정해주는 어노테이션은 다음과 같습니다.
- @Before : Advice 의 Target 메서드가 호출되기 전에 실행
- @After : Advice 의 Target 메서드가 호출된 후에 실행
- @AfterReturning : Target 메서드가 정상적으로 실행되어 반환값을 반환한 경우 실행
- @AfterThrowingAdvice : Target 메서드에서 Exception이 발생했을 때 실행
- @Around : Target메서드의 전과 후에 실행
AOP 적용 예시
※ AspectJ
기본적으로 제공되는 Spring AOP로는 다양한 기법(pointcut 등)의 AOP를 사용할 수 없기 때문에, AspectJ는 AOP를 유용하게 사용하기 위해 꼭 필요한 라이브러리 입니다.
Spring boot안에 기본적으로 포함되어 있기 때문에 별도로 설치할 필요는 없습니다.
먼저 간단한 RestApiController를 만들어 보겠습니다.
import com.example.test1.dto.User;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/api")
public class RestApiController {
@GetMapping("/get/{id}")
public String get(@PathVariable Long id, @RequestParam String name){
System.out.println("get method id:"+id+" name :"+name);
return id+" "+name;
}
@PostMapping("/post")
public User post(@RequestBody User user){
return user;
}
}
기본적인 get, post 요청을 받는 api를 정의했습니다. 이제 AOP클래스를 만들어보겠습니다.
@Aspect
@Component
public class ParameterAop {
@Pointcut("execution(* com.example.test1.controller..*.*(..))")
//controller패키지에 있는 모든 메서드에 설정
private void cut(){}
@Before("cut()")
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")
// returning은 target object의 리턴 값을 받아온다는 것을 의미
public void afterReturn(JoinPoint joinPoint, Object returnObj){
System.out.println("return obj");
System.out.println(returnObj);
}
}
@Aspect 어노테이션으로 해당 클래스가 Aspect임을 알리고 @Component 어노테이션으로 IoC 컨테이너에 해당 클래스를 등록합니다.
@Pointcut("execution(* com.example.test1.controller..*.*(..))")
private void cut(){}
@Pointcut()의 파라미터로는 pointcut 표현식이 들어가며 위 표현식은 com.example.test1.controller 패키지 하위의 모든 클래스에 pointcut이 적용된다는 의미입니다.
@Before("cut()")
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);
}
}
before이라는 Advice에 위에서 정의한 cut이라는 Pointcut이 @Before("cut()") 어노테이션을 통해 적용되었습니다.
method.getName()을 통해 해당 Advice가 적용된 메서드의 이름을 알아낼 수 있으며, jointPoint.getArgs()로는 메서드에 들어가는 파라미터들의 배열을 알아낼 수 있습니다.
브라우저에 "http://localhost:8080/api/get/100?name=JH" 로 api를 쏘면
AOP가 정상적으로 적용된 것을 확인할 수 있습니다.
'Spring' 카테고리의 다른 글
[SpringBoot] application.properties에 환경변수 설정하기 (@ConfigurationProperties) (0) | 2022.01.10 |
---|---|
[SpringBoot] @Component vs @Bean vs @Configuration (0) | 2022.01.10 |
[SpringCore] Validation (유효성 검증) (0) | 2021.12.27 |
[SpringCore] Custom Annotation과 AOP로 메서드 실행시간 측정하기 (0) | 2021.12.25 |
[SpringCore] IoC와 DI (0) | 2021.12.22 |