Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
Tags
- AOP
- db
- 스프링 핵심 원리
- springdatajpa
- Spring Boot
- Thymeleaf
- QueryDSL
- JDBC
- 알고리즘
- 스프링
- Android
- http
- Proxy
- 김영한
- jpa
- 그리디
- JPQL
- spring
- pointcut
- 인프런
- Exception
- Servlet
- Greedy
- transaction
- 자바
- 백준
- SpringBoot
- 스프링 핵심 기능
- java
- kotlin
Archives
- Today
- Total
개발자되기 프로젝트
[스프링AOP] 스프링AOP 구현 - 여러 Advice 본문
추가로 트랜잭션을 적용하는 코드도 추가해 보자. 기능이 동작한 것 처럼 로그만 남겨보자.
트랜잭션 기능은 보통 다음과 같이 동작한다.
- 핵심 로직 실행 직전에 트랜잭션을 시작
- 핵심 로직 실행
- 핵심 로직 실행에 문제가 없으면 커밋
- 핵심 로직 실행에 예외가 발생하면 롤백
1. AspectV3
@Slf4j
@Aspect
public class AspectV3 {
//hello.aop.order 패키지와 하위 패키지
@Pointcut("execution(* hello.aop.order..*(..))")
private void allOrder(){ } // pointcut signature
//클래스 이름 패턴이 *Service
@Pointcut("execution(* *..*Service.*(..))")
private void allService(){}
@Around("allOrder()")
public Object doLog(ProceedingJoinPoint joinPoint) throws Throwable{
log.info("[[log] {}", joinPoint.getSignature());
return joinPoint.proceed(); //target호출
}
//hello.aop.order 패키지와 하위 패키지이면서, 클래스 이름 패턴이 *Service
@Around("allOrder() && allService()")
public Object doTransaction(ProceedingJoinPoint joinPoint) throws Throwable{
try{
log.info("[트랜잭션 시작] {}", joinPoint.getSignature());
Object result = joinPoint.proceed();
log.info("[트랜잭션 커밋] {}", joinPoint.getSignature());
return result;
}catch (Exception e){
log.info("[트랜잭션 롤백] {}", joinPoint.getSignature());
throw e;
}finally {
log.info("[리로스 릴리즈] {}", joinPoint.getSignature());
}
}
}
- allOrder() 포인트컷은 hello.aop.order 패키지와 하위 패키지를 대상으로 한다.
- allService() 포인트컷은 타입 이름 패턴이 *Service 를 대상으로 하는데 쉽게 이야기해서
XxxService 처럼 Service 로 끝나는 것을 대상으로 한다.
*Servi* 과 같은 패턴도 가능하다. - 여기서 타입 이름 패턴이라고 한 이유는 클래스, 인터페이스에 모두 적용되기 때문이다.
- @Around("allOrder() && allService()")
- 포인트컷은 이렇게 조합할 수 있다.
- && (AND), || (OR), ! (NOT) 3가지 조합이 가능하다.
- hello.aop.order 패키지와 하위 패키지 이면서 타입 이름 패턴이 *Service 인 것을 대상으로 한다.
- 결과적으로 doTransaction() 어드바이스는 OrderService 에만 적용된다.
- doLog() 어드바이스는 OrderService , OrderRepository 에 모두 적용된다.
- 포인트것이 적용된 AOP
orderService : doLog() , doTransaction() 어드바이스 적용
orderRepository : doLog() 어드바이스 적용
2. 실행
@Slf4j
@SpringBootTest
//@Import(AspectV1.class) //스프링 빈으로 등록
//@Import(AspectV2.class) //스프링 빈으로 등록
@Import(AspectV3.class) //스프링 빈으로 등록
public class AopTest {
@Autowired
OrderService orderService;
@Autowired
OrderRepository orderRepository;
@Test
void aopInfo(){
log.info("isAopProxy, orderService={}", AopUtils.isAopProxy(orderService));
log.info("isAopProxy, orderRepository={}", AopUtils.isAopProxy(orderRepository));
}
@Test
void success(){
orderService.orderItem("itemA");
}
@Test
void exception(){
assertThatThrownBy(() -> orderService.orderItem("ex")).isInstanceOf(IllegalStateException.class);
}
}
- success() 결과
[[log] void hello.aop.order.OrderService.orderItem(String)
[트랜잭션 시작] void hello.aop.order.OrderService.orderItem(String)
[orderService] 실행
[[log] String hello.aop.order.OrderRepository.save(String)
[orderRepository] 실행
[트랜잭션 커밋] void hello.aop.order.OrderService.orderItem(String)
[리로스 릴리즈] void hello.aop.order.OrderService.orderItem(String)
- exception() 결과
rollback 호출
[[log] void hello.aop.order.OrderService.orderItem(String)
[트랜잭션 시작] void hello.aop.order.OrderService.orderItem(String)
[orderService] 실행
[[log] String hello.aop.order.OrderRepository.save(String)
[orderRepository] 실행
[트랜잭션 롤백] void hello.aop.order.OrderService.orderItem(String)
[리로스 릴리즈] void hello.aop.order.OrderService.orderItem(String)
3. AOP 적용 전 후
- AOP 적용 전
클라이언트 --> orderService.orderItem() --> orderRepository.save() - AOP 적용 후
클라이언트 --> [ doLog() --> doTransaction() ] --> orderService.orderItem() --> [ doLog() ] --> orderRepository.save() - orderService 에는 doLog() , doTransaction() 두가지 어드바이스가 적용되어 있고,
orderRepository 에는 doLog() 하나의 어드바이스만 적용된 것을 확인할 수 있다.
4. ?????????
- 어드바이스가 적용되는 순서를 변경하고 싶으면???????
- 예를 들어서 실행 시간을 측정해야 하는데 트랜잭션과 관련된 시간을 제외하고 측정하고 싶다?
- [ doTransaction() doLog() ] 이렇게 트랜잭션 이후에 로그를 남겨야 할 것이다.
5. GitHub :220105 SpringAOP - multiAdvice
'인프런 > [인프런] 스프링 핵심 원리 - 고급' 카테고리의 다른 글
[스프링AOP] 스프링AOP 구현 - Advice 순서 (0) | 2022.01.05 |
---|---|
[스프링AOP] 스프링AOP 구현 - Pointcut 참조 (0) | 2022.01.05 |
[스프링AOP] 스프링AOP 구현 - pointcut 분리 (0) | 2022.01.05 |
[스프링AOP] 스프링AOP 구현 (0) | 2022.01.05 |
[스프링AOP] 예제 프로젝트 (0) | 2022.01.05 |
Comments