๐ก ๊น์ํ๋์ ์คํ๋ง ํต์ฌ ์๋ฆฌ ๊ณ ๊ธํธ ๊ฐ์๋ฅผ ๋ฃ๊ณ ์ ๋ฆฌํ ๋ด์ฉ์
๋๋ค.
@Aspect ์ฌ์ฉํ์ฌ AOP ๊ตฌํ
@Slf4j
@Service
public class OrderService {
private final OrderRepository orderRepository;
public OrderService(OrderRepository orderRepository) {
this.orderRepository = orderRepository;
}
public void orderItem(String itemId) {
log.info("[orderService] ์คํ");
orderRepository.save(itemId);
}
}
@Slf4j
@Repository
public class OrderRepository {
public String save(String itemId) {
log.info("[orderRepository] ์คํ");
//์ ์ฅ ๋ก์ง
if (itemId.equals("ex")) {
throw new IllegalStateException("์์ธ ๋ฐ์!");
}
return "ok";
}
}
@Slf4j
@Aspect
public class AspectV1 {
//hello.aop.order ํจํค์ง์ ํ์ ํจํค์ง
@Around("execution(* hello.aop.order..*(..))")
public Object doLog(ProceedingJoinPoint joinPoint) throws Throwable {
log.info("[log] {}", joinPoint.getSignature()); //join point ์๊ทธ๋์ฒ
return joinPoint.proceed();
}
}
@Slf4j
@SpringBootTest
@Import(AspectV1.class)
public class AopTest {
@Autowired
OrderService orderService;
@Autowired
OrderRepository orderRepository;
...
@Test
void success() {
orderService.orderItem("itemA");
}
...
}
joinPoint.proceed()
joinPoint.proceed()์ ๋ฆฌํด์ ์ฃผ๋ก ํ๊น ๋ฉ์๋์ ๊ฒฐ๊ณผ๋ค.
ํ๊น ๋ฉ์๋์ ๊ฒฐ๊ณผ๊ฐ ์๋ค๋ฉด result๋ฅผ ๊ฐ์ง๊ณ ์ฌ๋ฌ๊ฐ์ง๋ฅผ ํ ์ ์๋ค.
์๋ฅผ ๋ค์ด ๊ฒฐ๊ณผ๋ฅผ ๋ก๊น ํ ์๋ ์๊ณ , ๊ฒฐ๊ณผ๋ก ๋ฐ์ ๊ฐ์ ๋ณํํด์ ๋ค์ ํด๋ผ์ด์ธํธ์ ์ ๋ฌํด์ค ์๋ ์๋ค.
๋ํ ๊ฒฐ๊ณผ๋ก ๋ฐ์ ๊ฐ์ ๋ํด ๊ฒ์ฆ์ ํด์ค ์๋ ์๋ค.
return ํ๋๊ณณ
return ํ๊ฒ ๋๋ฉด ํด๋น ํ๊น ๋ฉ์๋๋ฅผ ํธ์ถํ ํด๋ผ์ด์ธํธ์๊ฒ ์ ๋ฌ๋๋ค.
์๋ฅผ ๋ค์ด ํ๊น ๋ฉ์๋๊ฐ ๋ฐํ๊ฐ์ด ์๋ ๋ฉ์๋๋ผ๋ฉด ์ด๋ฅผ ํธ์ถํ ํด๋ผ์ด์ธํธ์์๋ ๋ฐํ๊ฐ์ ๋ฐ์์ ์ฒ๋ฆฌํด์ผ ํ๊ธฐ ๋๋ฌธ์ด๋ค.
์๋ ํ๋ก์ ๋ฑ๋ก ๊ณผ์
์คํ๋ง ๋ถํธ ์๋ ์ค์ ์ผ๋ก "AnnotationAwareAspectJAutoProxyCreator" ์ด๋ผ๋ ์๋ ํ๋ก์ ์์ฑ๊ธฐ๊ฐ ๋น ๋ฑ๋ก๋์ด ์๋๋ฐ, ์ด ์๋ ํ๋ก์ ์์ฑ๊ธฐ๊ฐ @Aspect๊ฐ ๋ถ์ ํด๋์ค๋ฅผ ๋ณด๊ณ Advisor(์ด๋๋ฐ์ด์ )๋ก ๋ณํํด ์ ์ฅํด์ค๋ค. ๊ทธ๋ฆฌ๊ณ ์ด Advisor(์ด๋๋ฐ์ด์ )๋ฅผ ๋ณด๊ณ ํฌ์ธํธ์ปท์ ๋์์ด ๋๋ ๊ฒ๋ค์ "ProxyFactory"์ ์ธ์๋ก ๋๊ฒจ ์๋์ผ๋ก ํ๋ก์๋ฅผ ์์ฑํ๊ณ ์ ์ฉํด์ค๋ค.
ProceedingJoinPoint๋ ๋ฌด์จ ์ฐ๊ด๊ด๊ณ๊ฐ ์์ด์ ํ๊ฒ์ ๋ํ ์ ๋ณด๋ค์ ์๊ณ ์๋์ง?
ProceedingJoinPoint
๊ฒฐ๊ตญ ํ๋ก์์ด๊ธฐ ๋๋ฌธ์ ํ์ผ์ ๋ํ ์ ๋ณด๋ฅผ ๊ฐ์ง๊ณ ์์ด์ผ ํธ์ถ์ ํ ์ ์๋ค. ํ์ผ์ ๋ํ ์ ๋ณด๊ฐ ์์ผ๋ ์ด ์ ๋ณด๋ค์ ์ฌ์ฉํ๊ธฐ ํธ๋ฆฌํ๊ฒ ProceedingJoinPoint ๊ฐ์ ๊ฐ์ฒด๋ฅผ ๋ง๋ค ์ ์๋ค. ์ฐธ๊ณ ๋ก ์คํ๋ง AOP๋ ํ๋ก์ ๊ฐ์ฒด๋ฅผ ์์ฑํ๊ณ , ์ด ํ๋ก์ ๊ฐ์ฒด๋ ์๋ณธ ๊ฐ์ฒด์ ๋ฉ์๋๋ฅผ ํธ์ถํ๋ ๋์ ์ถ๊ฐ์ ์ธ ๋์์ ์ํํ๋ค. ์ด ํ๋ก์ ๊ฐ์ฒด๊ฐ ๋ฉ์๋๋ฅผ ํธ์ถํ ๋ ProceedingJoinPoint ๊ฐ์ฒด๋ฅผ ์์ฑํ๊ณ ์ด๋ฅผ advice์ ์ ๋ฌํ๋ค. ๋ฐ๋ผ์ ProceedingJoinPoint๋ ํ๋ก์๊ฐ ๋ฉ์๋๋ฅผ ํธ์ถํ๋ ์์ ์ ์ ๋ณด๋ฅผ ๊ฐ์ง๊ฒ ๋๋ค.
์คํ - success()
ํ ์คํธ๋ฅผ ์คํํด๋ณด๋ฉด ๋ค์๊ณผ ๊ฐ์ด ๋ก๊ทธ๊ฐ ์ ์ถ๋ ฅ๋๋ ๊ฒ์ ํ์ธํ ์ ์๋ค.
[log] void hello.aop.order.OrderService.orderItem(String)
[orderService] ์คํ
[log] String hello.aop.order.OrderRepository.save(String)
[orderRepository] ์คํ
์คํ ํ๋ฆ

AOP - ํฌ์ธํธ์ปท ๋ถ๋ฆฌํ๊ธฐ
@Around์ ํฌ์ธํธ์ปท ํํ์์ ์ง์ ๋ฃ์ ์ ๋ ์์ง๋ง, @Pointcut ์ ๋ ธํ ์ด์ ์ ์ฌ์ฉํด์ ๋ณ๋๋ก ๋ถ๋ฆฌํ ์ ๋ ์๋ค.
@Slf4j
@Aspect
public class AspectV2 {
//hello.aop.order ํจํค์ง์ ํ์ ํจํค์ง
@Pointcut("execution(* hello.aop.order..*(..))")
private void allOrder(){} //pointcut signature
@Around("allOrder()")
public Object doLog(ProceedingJoinPoint joinPoint) throws Throwable {
log.info("[log] {}", joinPoint.getSignature()); //join point ์๊ทธ๋์ฒ
return joinPoint.proceed();
}
}
@Pointcut
@Pointcut์ ํฌ์ธํธ์ปท ํํ์์ ์ฌ์ฉํ๋ค.
๋ฉ์๋ ์ด๋ฆ๊ณผ ํ๋ผ๋ฏธํฐ๋ฅผ ํฉ์ณ์ ํฌ์ธํธ์ปท ์๊ทธ๋์ฒ(signature)๋ผ ํ๋ค.
๋ฉ์๋์ ๋ฐํ ํ์
์ void์ฌ์ผ ํ๋ค. ์ฝ๋ ๋ด์ฉ์ ๋น์๋๋ค.
ํฌ์ธํธ์ปท ์๊ทธ๋์ฒ๋ allOrder()์ด๋ค. ์ด๋ฆ ๊ทธ๋๋ก ์ฃผ๋ฌธ๊ณผ ๊ด๋ จ๋ ๋ชจ๋ ๊ธฐ๋ฅ์ ๋์์ผ๋ก ํ๋ ํฌ์ธํธ์ปท์ด๋ค.
@Around ์ด๋๋ฐ์ด์ค์์๋ ํฌ์ธํธ์ปท์ ์ง์ ์ง์ ํด๋ ๋์ง๋ง, ํฌ์ธํธ์ปท ์๊ทธ๋์ฒ๋ฅผ ์ฌ์ฉํด๋ ๋๋ค.
์ฌ๊ธฐ์๋ @Around("allOrder()")๋ฅผ ์ฌ์ฉํ๋ค
private, public ๊ฐ์ ์ ๊ทผ ์ ์ด์๋ ๋ด๋ถ์์๋ง ์ฌ์ฉํ๋ฉด private์ ์ฌ์ฉํด๋ ๋์ง๋ง, ๋ค๋ฅธ ์ ์คํฉํธ์์ ์ฐธ๊ณ ํ๋ ค๋ฉด public์ ์ฌ์ฉํด์ผ ํ๋ค. ๊ฒฐ๊ณผ์ ์ผ๋ก AspectV1๊ณผ ๊ฐ์ ๊ธฐ๋ฅ์ ์ํํ๋ค.
์ด๋ ๊ฒ ๋ถ๋ฆฌํ๋ฉด ํ๋์ ํฌ์ธํธ์ปท ํํ์์ ์ฌ๋ฌ ์ด๋๋ฐ์ด์ค์์ ํจ๊ป ์ฌ์ฉํ ์ ์๋ค.
๊ทธ๋ฆฌ๊ณ ๋ค๋ฅธ ํด๋์ค์ ์๋ ์ธ๋ถ ์ด๋๋ฐ์ด์ค์์๋ ํฌ์ธํธ์ปท์ ํจ๊ป ์ฌ์ฉํ ์ ์๋ค.
์คํ - success()
ํ ์คํธ๋ฅผ ์คํํด๋ณด๋ฉด ๋ค์๊ณผ ๊ฐ์ด ๋ก๊ทธ๊ฐ ์ ์ถ๋ ฅ๋๋ ๊ฒ์ ํ์ธํ ์ ์๋ค.
[log] void hello.aop.order.OrderService.orderItem(String)
[orderService] ์คํ
[log] String hello.aop.order.OrderRepository.save(String)
[orderRepository] ์คํ
AOP - ์ด๋๋ฐ์ด์ค ์ถ๊ฐ ๊ตฌํ
์์ ๋ก๊ทธ๋ฅผ ์ถ๋ ฅํ๋ ๊ธฐ๋ฅ์ ์ถ๊ฐ๋ก ํธ๋์ญ์ ์ ์ ์ฉํ๋ ์ฝ๋๋ ์ถ๊ฐํด๋ณด์.
์ฌ๊ธฐ์๋ ์ง์ง ํธ๋์ญ์ ์ ์คํํ๋ ๊ฒ์ ์๋๋ค. ๊ธฐ๋ฅ์ด ๋์ํ ๊ฒ ์ฒ๋ผ ๋ก๊ทธ๋ง ๋จ๊ธฐ๊ฒ ๋ค.
@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()); //join point ์๊ทธ๋์ฒ
return joinPoint.proceed();
}
//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์ ๋ชจ๋ ์ ์ฉ๋๋ค.
์คํ - 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)
ํฌ์ธํธ์ปท ๊ณต์ฉ์ผ๋ก ์ฌ์ฉํ๊ธฐ
ํฌ์ธํธ์ปท์ ๊ณต์ฉ์ผ๋ก ์ฌ์ฉํ๊ธฐ ์ํด ๋ณ๋์ ์ธ๋ถ ํด๋์ค์ ๋ชจ์๋์ด๋ ๋๋ค.
์ฐธ๊ณ ๋ก ์ธ๋ถ์์ ํธ์ถํ ๋๋ ํฌ์ธํธ์ปท์ ์ ๊ทผ ์ ์ด์๋ฅผ public์ผ๋ก ์ด์ด๋์ด์ผ ํ๋ค.
public class Pointcuts {
//hello.aop.order ํจํค์ง์ ํ์ ํจํค์ง
@Pointcut("execution(* hello.aop.order..*(..))")
public void allOrder(){} //pointcut signature
//ํด๋์ค ์ด๋ฆ ํจํด์ด *Service
@Pointcut("execution(* *..*Service.*(..))")
public void allService(){}
//allOrder && allService
@Pointcut("allOrder() && allService()")
public void orderAndService() {}
}
orderAndService(): allOrder() ํฌ์ธํธ์ปท์ allService() ํฌ์ธํธ์ปท์ ์กฐํฉํด์ ์๋ก์ด ํฌ์ธํธ์ปท์ ๋ง๋ค์๋ค.
@Slf4j
@Aspect
public class AspectV4Pointcut {
@Around("hello.aop.order.aop.Pointcuts.allOrder()")
public Object doLog(ProceedingJoinPoint joinPoint) throws Throwable {
log.info("[log] {}", joinPoint.getSignature()); //join point ์๊ทธ๋์ฒ
return joinPoint.proceed();
}
@Around("hello.aop.order.aop.Pointcuts.orderAndService()")
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());
}
}
}
์ฌ์ฉํ๋ ๋ฐฉ๋ฒ์ ํจํค์ง๋ช ์ ํฌํจํ ํด๋์ค ์ด๋ฆ๊ณผ ํฌ์ธํธ์ปท ์๊ทธ๋์ฒ๋ฅผ ๋ชจ๋ ์ง์ ํ๋ฉด ๋๋ค.
- hello.aop.order.aop.Pointcuts.allOrder()
- ํจํค์ง๋ช .ํด๋์ค์ด๋ฆ
ํฌ์ธํธ์ปท์ ์ฌ๋ฌ ์ด๋๋ฐ์ด์ค์์ ํจ๊ป ์ฌ์ฉํ ๋ ์ด ๋ฐฉ๋ฒ์ ์ฌ์ฉํ๋ฉด ํจ๊ณผ์ ์ด๋ค.
AOP - ์ด๋๋ฐ์ด์ค ์์ ์ง์ ํ๊ธฐ
์ด๋๋ฐ์ด์ค๋ ๊ธฐ๋ณธ์ ์ผ๋ก ์์๋ฅผ ๋ณด์ฅํ์ง ์๋๋ค. ์์๋ฅผ ์ง์ ํ๊ณ ์ถ์ผ๋ฉด @Aspect ์ ์ฉ ๋จ์๋ก org.springframework.core.annotation.@Order ์ ๋ ธํ ์ด์ ์ ์ ์ฉํด์ผ ํ๋ค. ๋ฌธ์ ๋ ์ด๊ฒ์ ์ด๋๋ฐ์ด์ค ๋จ์๊ฐ ์๋๋ผ ํด๋์ค ๋จ์๋ก ์ ์ฉํ ์ ์๋ค๋ ์ ์ด๋ค.
๊ทธ๋์ ์ง๊ธ์ฒ๋ผ ํ๋์ ์ ์คํํธ์ ์ฌ๋ฌ ์ด๋๋ฐ์ด์ค๊ฐ ์์ผ๋ฉด ์์๋ฅผ ๋ณด์ฅ ๋ฐ์ ์ ์๋ค.
๋ฐ๋ผ์ ์ ์คํํธ๋ฅผ ๋ณ๋์ ํด๋์ค๋ก ๋ถ๋ฆฌํด์ผ ํ๋ค.
ํ์ฌ ๋ก๊ทธ๋ฅผ ๋จ๊ธฐ๋ ์์๊ฐ ์๋ง๋ [doLog() -> doTransaction()]์ธ๋ฐ ๋ก๊ทธ๋ฅผ ๋จ๊ธฐ๋ ์์๋ฅผ ๋ฐ๊พธ์ด์ [doTransaction() -> doLog()] ๋๋๋ก ๋ณ๊ฒฝํด๋ณด์.
@Slf4j
public class AspectV5Order {
@Aspect
@Order(2)
public static class LogAspect {
@Around("hello.aop.order.aop.Pointcuts.allOrder()")
public Object doLog(ProceedingJoinPoint joinPoint) throws Throwable {
log.info("[log] {}", joinPoint.getSignature()); //join point ์๊ทธ๋์ฒ
return joinPoint.proceed();
}
}
@Aspect
@Order(1)
public static class TxAspect {
@Around("hello.aop.order.aop.Pointcuts.orderAndService()")
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());
}
}
}
}
ํ๋์ ์ ์คํํธ ์์ ์๋ ์ด๋๋ฐ์ด์ค๋ฅผ LogAspect, TxAspect ์ ์คํํธ๋ก ๊ฐ๊ฐ ๋ถ๋ฆฌํ๋ค.
๊ทธ๋ฆฌ๊ณ ๊ฐ ์ ์คํํธ์ @Order ์ ๋ ธํ ์ด์ ์ ํตํด ์คํ ์์๋ฅผ ์ ์ฉํ๋ค. ์ฐธ๊ณ ๋ก ์ซ์๊ฐ ์์์๋ก ๋จผ์ ์คํ๋๋ค.
์คํ ๊ฒฐ๊ณผ
[ํธ๋์ญ์
์์] void hello.aop.order.OrderService.orderItem(String)
[log] 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)
์ด๋๋ฐ์ด์ค ์ข ๋ฅ
@Slf4j
@Aspect
public class AspectV6Advice {
@Around("hello.aop.order.aop.Pointcuts.orderAndService()")
public Object doTransaction(ProceedingJoinPoint joinPoint) throws Throwable {
try {
//@Before
log.info("[ํธ๋์ญ์
์์] {}", joinPoint.getSignature());
Object result = joinPoint.proceed();
//@AfterReturning
log.info("[ํธ๋์ญ์
์ปค๋ฐ] {}", joinPoint.getSignature());
return result;
} catch (Exception e) {
//@AfterThrowing
log.info("[ํธ๋์ญ์
๋กค๋ฐฑ] {}", joinPoint.getSignature());
throw e;
} finally {
//@After
log.info("[๋ฆฌ์์ค ๋ฆด๋ฆฌ์ฆ] {}", joinPoint.getSignature());
}
}
@Before("hello.aop.order.aop.Pointcuts.orderAndService()")
public void doBefore(JoinPoint joinPoint) {
log.info("[before] {}", joinPoint.getSignature());
}
@AfterReturning(value = "hello.aop.order.aop.Pointcuts.orderAndService()", returning = "result")
public void doReturn(JoinPoint joinPoint, Object result) {
log.info("[return] {} return={}", joinPoint.getSignature(), result);
}
@AfterThrowing(value = "hello.aop.order.aop.Pointcuts.orderAndService()", throwing = "ex")
public void doThrowing(JoinPoint joinPoint, Exception ex) {
log.info("[ex] {} message={}", ex);
}
@After(value = "hello.aop.order.aop.Pointcuts.orderAndService()")
public void doAfter(JoinPoint joinPoint) {
log.info("[after] {}", joinPoint.getSignature());
}
}
์ด๋๋ฐ์ด์ค ์ข ๋ฅ
@Before
- ์กฐ์ธ ํฌ์ธํธ ์คํ ์
@AfterReturning
- ๋ฉ์๋ ์คํ์ด ์ ์์ ์ผ๋ก ๋ฐํ๋ ๋ ์คํ
@AfterThrowing
- ๋ฉ์๋ ์คํ์ด ์์ธ๋ฅผ ๋์ ธ์ ์ข ๋ฃ๋ ๋ ์คํ
@After
- ๋ฉ์๋ ์คํ์ด ์ข ๋ฃ๋๋ฉด ์คํ๋๋ค. (finally๋ฅผ ์๊ฐํ๋ฉด ๋๋ค.)
- ์ ์ ๋ฐ ์์ธ ๋ฐํ ์กฐ๊ฑด์ ๋ชจ๋ ์ฒ๋ฆฌํ๋ค.
-
์ผ๋ฐ์ ์ผ๋ก ๋ฆฌ์์ค๋ฅผ ํด์ ํ๋ ๋ฐ ์ฌ์ฉํ๋ค.
@Around
- ๋ฉ์๋์ ์คํ์ ์ฃผ๋ณ์์ ์คํ๋๋ค.
- ๋ฉ์๋ ์คํ ์ ํ์ ์์ ์ ์ํํ๋ค. ๊ฐ์ฅ ๊ฐ๋ ฅํ ์ด๋๋ฐ์ด์ค
- ์ด๋๋ฐ์ด์ค์ ์ฒซ ๋ฒ์งธ ํ๋ผ๋ฏธํฐ๋ ProceedingJoinPoint๋ฅผ ์ฌ์ฉํด์ผ ํ๋ค.
- proceed()๋ฅผ ํตํด ๋์์ ์คํํ๋ค.
- proceed()๋ฅผ ์ฌ๋ฌ๋ฒ ์คํํ ์๋ ์์(์ฌ์๋)
์ฐธ๊ณ ์ ๋ณด ํ๋
๋ชจ๋ ์ด๋๋ฐ์ด์ค๋ org.aspectj.lang.JoinPoint๋ฅผ ์ฒซ๋ฒ์งธ ํ๋ผ๋ฏธํฐ์ ์ฌ์ฉํ ์ ์๋ค. (์๋ตํด๋ ๋๋ค.)
๋จ @Around๋ ProceedingJoinPoint์ ์ฌ์ฉํด์ผ ํ๋ค.
์ฐธ๊ณ ๋ก ProceedingJoinPoint๋ org.aspectj.lang.JoinPoint์ ํ์ ํ์ ์ด๋ค.
JoinPoint ์ธํฐํ์ด์ค์ ์ฃผ์ ๊ธฐ๋ฅ
- getArgs(): ๋ฉ์๋ ์ธ์๋ฅผ ๋ฐํํฉ๋๋ค
- getThis(): ํ๋ก์ ๊ฐ์ฒด๋ฅผ ๋ฐํํฉ๋๋ค.
- getTarget(): ๋์ ๊ฐ์ฒด๋ฅผ ๋ฐํํฉ๋๋ค.
- getSignature(): ์กฐ์ธ๋๋ ๋ฉ์๋์ ๋ํ ์ค๋ช ์ ๋ฐํํฉ๋๋ค.
- toString(): ์กฐ์ธ๋๋ ๋ฐฉ๋ฒ์ ๋ํ ์ ์ฉํ ์ค๋ช ์ ์ธ์ํฉ๋๋ค.
ProceedingJoinPoint ์ธํฐํ์ด์ค์ ์ฃผ์ ๊ธฐ๋ฅ
- proceed(): ๋ค์ ์ด๋๋ฐ์ด์ค๋ ํ์ผ์ ํธ์ถํ๋ค.
์คํํ๋ฆ

์์
- ์คํ๋ง์ 5.2.7 ๋ฒ์ ๋ถํฐ ๋์ผํ @Aspect์์์ ๋์ผํ ์กฐ์ธํฌ์ธํธ์ ์ฐ์ ์์๋ฅผ ์ ํ๋ค.
- ์คํ ์์: @Around, @Before, @After, @AfterReturning, @AfterThrowing
- ์ด๋๋ฐ์ด์ค๊ฐ ์ ์ฉ๋๋ ์์๋ ์ด๋ ๊ฒ ์ ์ฉ๋์ง๋ง, ํธ์ถ ์์์ ๋ฆฌํด ์์๋ ๋ฐ๋๋ผ๋ ์ ์ ์์๋์.
- ๋ฌผ๋ก @Aspect์์ ๋์ผํ ์ข ๋ฅ์ ์ด๋๋ฐ์ด์ค๊ฐ 2๊ฐ ์์ผ๋ฉด ์์๊ฐ ๋ณด์ฅ๋์ง ์๋๋ค.
- ์ด ๊ฒฝ์ฐ ์์ ๋ฐฐ์ด ๊ฒ ์ฒ๋ผ @Aspect๋ฅผ ๋ถ๋ฆฌํ๊ณ @Order๋ฅผ ์ ์ฉํ์.
'Spring > AOP' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
ํฌ์ธํธ์ปท ์ง์์ (2) | 2024.11.14 |
---|---|
์คํ๋ง AOP ๊ฐ๋ (0) | 2024.11.12 |
@Aspect AOP (0) | 2024.11.12 |
๋น ํ์ฒ๋ฆฌ๊ธฐ (0) | 2024.11.12 |
ํฌ์ธํธ์ปท, ์ด๋๋ฐ์ด์ค, ์ด๋๋ฐ์ด์ (0) | 2024.11.11 |
๐ก ๊น์ํ๋์ ์คํ๋ง ํต์ฌ ์๋ฆฌ ๊ณ ๊ธํธ ๊ฐ์๋ฅผ ๋ฃ๊ณ ์ ๋ฆฌํ ๋ด์ฉ์
๋๋ค.
@Aspect ์ฌ์ฉํ์ฌ AOP ๊ตฌํ
@Slf4j
@Service
public class OrderService {
private final OrderRepository orderRepository;
public OrderService(OrderRepository orderRepository) {
this.orderRepository = orderRepository;
}
public void orderItem(String itemId) {
log.info("[orderService] ์คํ");
orderRepository.save(itemId);
}
}
@Slf4j
@Repository
public class OrderRepository {
public String save(String itemId) {
log.info("[orderRepository] ์คํ");
//์ ์ฅ ๋ก์ง
if (itemId.equals("ex")) {
throw new IllegalStateException("์์ธ ๋ฐ์!");
}
return "ok";
}
}
@Slf4j
@Aspect
public class AspectV1 {
//hello.aop.order ํจํค์ง์ ํ์ ํจํค์ง
@Around("execution(* hello.aop.order..*(..))")
public Object doLog(ProceedingJoinPoint joinPoint) throws Throwable {
log.info("[log] {}", joinPoint.getSignature()); //join point ์๊ทธ๋์ฒ
return joinPoint.proceed();
}
}
@Slf4j
@SpringBootTest
@Import(AspectV1.class)
public class AopTest {
@Autowired
OrderService orderService;
@Autowired
OrderRepository orderRepository;
...
@Test
void success() {
orderService.orderItem("itemA");
}
...
}
joinPoint.proceed()
joinPoint.proceed()์ ๋ฆฌํด์ ์ฃผ๋ก ํ๊น ๋ฉ์๋์ ๊ฒฐ๊ณผ๋ค.
ํ๊น ๋ฉ์๋์ ๊ฒฐ๊ณผ๊ฐ ์๋ค๋ฉด result๋ฅผ ๊ฐ์ง๊ณ ์ฌ๋ฌ๊ฐ์ง๋ฅผ ํ ์ ์๋ค.
์๋ฅผ ๋ค์ด ๊ฒฐ๊ณผ๋ฅผ ๋ก๊น ํ ์๋ ์๊ณ , ๊ฒฐ๊ณผ๋ก ๋ฐ์ ๊ฐ์ ๋ณํํด์ ๋ค์ ํด๋ผ์ด์ธํธ์ ์ ๋ฌํด์ค ์๋ ์๋ค.
๋ํ ๊ฒฐ๊ณผ๋ก ๋ฐ์ ๊ฐ์ ๋ํด ๊ฒ์ฆ์ ํด์ค ์๋ ์๋ค.
return ํ๋๊ณณ
return ํ๊ฒ ๋๋ฉด ํด๋น ํ๊น ๋ฉ์๋๋ฅผ ํธ์ถํ ํด๋ผ์ด์ธํธ์๊ฒ ์ ๋ฌ๋๋ค.
์๋ฅผ ๋ค์ด ํ๊น ๋ฉ์๋๊ฐ ๋ฐํ๊ฐ์ด ์๋ ๋ฉ์๋๋ผ๋ฉด ์ด๋ฅผ ํธ์ถํ ํด๋ผ์ด์ธํธ์์๋ ๋ฐํ๊ฐ์ ๋ฐ์์ ์ฒ๋ฆฌํด์ผ ํ๊ธฐ ๋๋ฌธ์ด๋ค.
์๋ ํ๋ก์ ๋ฑ๋ก ๊ณผ์
์คํ๋ง ๋ถํธ ์๋ ์ค์ ์ผ๋ก "AnnotationAwareAspectJAutoProxyCreator" ์ด๋ผ๋ ์๋ ํ๋ก์ ์์ฑ๊ธฐ๊ฐ ๋น ๋ฑ๋ก๋์ด ์๋๋ฐ, ์ด ์๋ ํ๋ก์ ์์ฑ๊ธฐ๊ฐ @Aspect๊ฐ ๋ถ์ ํด๋์ค๋ฅผ ๋ณด๊ณ Advisor(์ด๋๋ฐ์ด์ )๋ก ๋ณํํด ์ ์ฅํด์ค๋ค. ๊ทธ๋ฆฌ๊ณ ์ด Advisor(์ด๋๋ฐ์ด์ )๋ฅผ ๋ณด๊ณ ํฌ์ธํธ์ปท์ ๋์์ด ๋๋ ๊ฒ๋ค์ "ProxyFactory"์ ์ธ์๋ก ๋๊ฒจ ์๋์ผ๋ก ํ๋ก์๋ฅผ ์์ฑํ๊ณ ์ ์ฉํด์ค๋ค.
ProceedingJoinPoint๋ ๋ฌด์จ ์ฐ๊ด๊ด๊ณ๊ฐ ์์ด์ ํ๊ฒ์ ๋ํ ์ ๋ณด๋ค์ ์๊ณ ์๋์ง?
ProceedingJoinPoint
๊ฒฐ๊ตญ ํ๋ก์์ด๊ธฐ ๋๋ฌธ์ ํ์ผ์ ๋ํ ์ ๋ณด๋ฅผ ๊ฐ์ง๊ณ ์์ด์ผ ํธ์ถ์ ํ ์ ์๋ค. ํ์ผ์ ๋ํ ์ ๋ณด๊ฐ ์์ผ๋ ์ด ์ ๋ณด๋ค์ ์ฌ์ฉํ๊ธฐ ํธ๋ฆฌํ๊ฒ ProceedingJoinPoint ๊ฐ์ ๊ฐ์ฒด๋ฅผ ๋ง๋ค ์ ์๋ค. ์ฐธ๊ณ ๋ก ์คํ๋ง AOP๋ ํ๋ก์ ๊ฐ์ฒด๋ฅผ ์์ฑํ๊ณ , ์ด ํ๋ก์ ๊ฐ์ฒด๋ ์๋ณธ ๊ฐ์ฒด์ ๋ฉ์๋๋ฅผ ํธ์ถํ๋ ๋์ ์ถ๊ฐ์ ์ธ ๋์์ ์ํํ๋ค. ์ด ํ๋ก์ ๊ฐ์ฒด๊ฐ ๋ฉ์๋๋ฅผ ํธ์ถํ ๋ ProceedingJoinPoint ๊ฐ์ฒด๋ฅผ ์์ฑํ๊ณ ์ด๋ฅผ advice์ ์ ๋ฌํ๋ค. ๋ฐ๋ผ์ ProceedingJoinPoint๋ ํ๋ก์๊ฐ ๋ฉ์๋๋ฅผ ํธ์ถํ๋ ์์ ์ ์ ๋ณด๋ฅผ ๊ฐ์ง๊ฒ ๋๋ค.
์คํ - success()
ํ ์คํธ๋ฅผ ์คํํด๋ณด๋ฉด ๋ค์๊ณผ ๊ฐ์ด ๋ก๊ทธ๊ฐ ์ ์ถ๋ ฅ๋๋ ๊ฒ์ ํ์ธํ ์ ์๋ค.
[log] void hello.aop.order.OrderService.orderItem(String)
[orderService] ์คํ
[log] String hello.aop.order.OrderRepository.save(String)
[orderRepository] ์คํ
์คํ ํ๋ฆ

AOP - ํฌ์ธํธ์ปท ๋ถ๋ฆฌํ๊ธฐ
@Around์ ํฌ์ธํธ์ปท ํํ์์ ์ง์ ๋ฃ์ ์ ๋ ์์ง๋ง, @Pointcut ์ ๋ ธํ ์ด์ ์ ์ฌ์ฉํด์ ๋ณ๋๋ก ๋ถ๋ฆฌํ ์ ๋ ์๋ค.
@Slf4j
@Aspect
public class AspectV2 {
//hello.aop.order ํจํค์ง์ ํ์ ํจํค์ง
@Pointcut("execution(* hello.aop.order..*(..))")
private void allOrder(){} //pointcut signature
@Around("allOrder()")
public Object doLog(ProceedingJoinPoint joinPoint) throws Throwable {
log.info("[log] {}", joinPoint.getSignature()); //join point ์๊ทธ๋์ฒ
return joinPoint.proceed();
}
}
@Pointcut
@Pointcut์ ํฌ์ธํธ์ปท ํํ์์ ์ฌ์ฉํ๋ค.
๋ฉ์๋ ์ด๋ฆ๊ณผ ํ๋ผ๋ฏธํฐ๋ฅผ ํฉ์ณ์ ํฌ์ธํธ์ปท ์๊ทธ๋์ฒ(signature)๋ผ ํ๋ค.
๋ฉ์๋์ ๋ฐํ ํ์
์ void์ฌ์ผ ํ๋ค. ์ฝ๋ ๋ด์ฉ์ ๋น์๋๋ค.
ํฌ์ธํธ์ปท ์๊ทธ๋์ฒ๋ allOrder()์ด๋ค. ์ด๋ฆ ๊ทธ๋๋ก ์ฃผ๋ฌธ๊ณผ ๊ด๋ จ๋ ๋ชจ๋ ๊ธฐ๋ฅ์ ๋์์ผ๋ก ํ๋ ํฌ์ธํธ์ปท์ด๋ค.
@Around ์ด๋๋ฐ์ด์ค์์๋ ํฌ์ธํธ์ปท์ ์ง์ ์ง์ ํด๋ ๋์ง๋ง, ํฌ์ธํธ์ปท ์๊ทธ๋์ฒ๋ฅผ ์ฌ์ฉํด๋ ๋๋ค.
์ฌ๊ธฐ์๋ @Around("allOrder()")๋ฅผ ์ฌ์ฉํ๋ค
private, public ๊ฐ์ ์ ๊ทผ ์ ์ด์๋ ๋ด๋ถ์์๋ง ์ฌ์ฉํ๋ฉด private์ ์ฌ์ฉํด๋ ๋์ง๋ง, ๋ค๋ฅธ ์ ์คํฉํธ์์ ์ฐธ๊ณ ํ๋ ค๋ฉด public์ ์ฌ์ฉํด์ผ ํ๋ค. ๊ฒฐ๊ณผ์ ์ผ๋ก AspectV1๊ณผ ๊ฐ์ ๊ธฐ๋ฅ์ ์ํํ๋ค.
์ด๋ ๊ฒ ๋ถ๋ฆฌํ๋ฉด ํ๋์ ํฌ์ธํธ์ปท ํํ์์ ์ฌ๋ฌ ์ด๋๋ฐ์ด์ค์์ ํจ๊ป ์ฌ์ฉํ ์ ์๋ค.
๊ทธ๋ฆฌ๊ณ ๋ค๋ฅธ ํด๋์ค์ ์๋ ์ธ๋ถ ์ด๋๋ฐ์ด์ค์์๋ ํฌ์ธํธ์ปท์ ํจ๊ป ์ฌ์ฉํ ์ ์๋ค.
์คํ - success()
ํ ์คํธ๋ฅผ ์คํํด๋ณด๋ฉด ๋ค์๊ณผ ๊ฐ์ด ๋ก๊ทธ๊ฐ ์ ์ถ๋ ฅ๋๋ ๊ฒ์ ํ์ธํ ์ ์๋ค.
[log] void hello.aop.order.OrderService.orderItem(String)
[orderService] ์คํ
[log] String hello.aop.order.OrderRepository.save(String)
[orderRepository] ์คํ
AOP - ์ด๋๋ฐ์ด์ค ์ถ๊ฐ ๊ตฌํ
์์ ๋ก๊ทธ๋ฅผ ์ถ๋ ฅํ๋ ๊ธฐ๋ฅ์ ์ถ๊ฐ๋ก ํธ๋์ญ์ ์ ์ ์ฉํ๋ ์ฝ๋๋ ์ถ๊ฐํด๋ณด์.
์ฌ๊ธฐ์๋ ์ง์ง ํธ๋์ญ์ ์ ์คํํ๋ ๊ฒ์ ์๋๋ค. ๊ธฐ๋ฅ์ด ๋์ํ ๊ฒ ์ฒ๋ผ ๋ก๊ทธ๋ง ๋จ๊ธฐ๊ฒ ๋ค.
@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()); //join point ์๊ทธ๋์ฒ
return joinPoint.proceed();
}
//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์ ๋ชจ๋ ์ ์ฉ๋๋ค.
์คํ - 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)
ํฌ์ธํธ์ปท ๊ณต์ฉ์ผ๋ก ์ฌ์ฉํ๊ธฐ
ํฌ์ธํธ์ปท์ ๊ณต์ฉ์ผ๋ก ์ฌ์ฉํ๊ธฐ ์ํด ๋ณ๋์ ์ธ๋ถ ํด๋์ค์ ๋ชจ์๋์ด๋ ๋๋ค.
์ฐธ๊ณ ๋ก ์ธ๋ถ์์ ํธ์ถํ ๋๋ ํฌ์ธํธ์ปท์ ์ ๊ทผ ์ ์ด์๋ฅผ public์ผ๋ก ์ด์ด๋์ด์ผ ํ๋ค.
public class Pointcuts {
//hello.aop.order ํจํค์ง์ ํ์ ํจํค์ง
@Pointcut("execution(* hello.aop.order..*(..))")
public void allOrder(){} //pointcut signature
//ํด๋์ค ์ด๋ฆ ํจํด์ด *Service
@Pointcut("execution(* *..*Service.*(..))")
public void allService(){}
//allOrder && allService
@Pointcut("allOrder() && allService()")
public void orderAndService() {}
}
orderAndService(): allOrder() ํฌ์ธํธ์ปท์ allService() ํฌ์ธํธ์ปท์ ์กฐํฉํด์ ์๋ก์ด ํฌ์ธํธ์ปท์ ๋ง๋ค์๋ค.
@Slf4j
@Aspect
public class AspectV4Pointcut {
@Around("hello.aop.order.aop.Pointcuts.allOrder()")
public Object doLog(ProceedingJoinPoint joinPoint) throws Throwable {
log.info("[log] {}", joinPoint.getSignature()); //join point ์๊ทธ๋์ฒ
return joinPoint.proceed();
}
@Around("hello.aop.order.aop.Pointcuts.orderAndService()")
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());
}
}
}
์ฌ์ฉํ๋ ๋ฐฉ๋ฒ์ ํจํค์ง๋ช ์ ํฌํจํ ํด๋์ค ์ด๋ฆ๊ณผ ํฌ์ธํธ์ปท ์๊ทธ๋์ฒ๋ฅผ ๋ชจ๋ ์ง์ ํ๋ฉด ๋๋ค.
- hello.aop.order.aop.Pointcuts.allOrder()
- ํจํค์ง๋ช .ํด๋์ค์ด๋ฆ
ํฌ์ธํธ์ปท์ ์ฌ๋ฌ ์ด๋๋ฐ์ด์ค์์ ํจ๊ป ์ฌ์ฉํ ๋ ์ด ๋ฐฉ๋ฒ์ ์ฌ์ฉํ๋ฉด ํจ๊ณผ์ ์ด๋ค.
AOP - ์ด๋๋ฐ์ด์ค ์์ ์ง์ ํ๊ธฐ
์ด๋๋ฐ์ด์ค๋ ๊ธฐ๋ณธ์ ์ผ๋ก ์์๋ฅผ ๋ณด์ฅํ์ง ์๋๋ค. ์์๋ฅผ ์ง์ ํ๊ณ ์ถ์ผ๋ฉด @Aspect ์ ์ฉ ๋จ์๋ก org.springframework.core.annotation.@Order ์ ๋ ธํ ์ด์ ์ ์ ์ฉํด์ผ ํ๋ค. ๋ฌธ์ ๋ ์ด๊ฒ์ ์ด๋๋ฐ์ด์ค ๋จ์๊ฐ ์๋๋ผ ํด๋์ค ๋จ์๋ก ์ ์ฉํ ์ ์๋ค๋ ์ ์ด๋ค.
๊ทธ๋์ ์ง๊ธ์ฒ๋ผ ํ๋์ ์ ์คํํธ์ ์ฌ๋ฌ ์ด๋๋ฐ์ด์ค๊ฐ ์์ผ๋ฉด ์์๋ฅผ ๋ณด์ฅ ๋ฐ์ ์ ์๋ค.
๋ฐ๋ผ์ ์ ์คํํธ๋ฅผ ๋ณ๋์ ํด๋์ค๋ก ๋ถ๋ฆฌํด์ผ ํ๋ค.
ํ์ฌ ๋ก๊ทธ๋ฅผ ๋จ๊ธฐ๋ ์์๊ฐ ์๋ง๋ [doLog() -> doTransaction()]์ธ๋ฐ ๋ก๊ทธ๋ฅผ ๋จ๊ธฐ๋ ์์๋ฅผ ๋ฐ๊พธ์ด์ [doTransaction() -> doLog()] ๋๋๋ก ๋ณ๊ฒฝํด๋ณด์.
@Slf4j
public class AspectV5Order {
@Aspect
@Order(2)
public static class LogAspect {
@Around("hello.aop.order.aop.Pointcuts.allOrder()")
public Object doLog(ProceedingJoinPoint joinPoint) throws Throwable {
log.info("[log] {}", joinPoint.getSignature()); //join point ์๊ทธ๋์ฒ
return joinPoint.proceed();
}
}
@Aspect
@Order(1)
public static class TxAspect {
@Around("hello.aop.order.aop.Pointcuts.orderAndService()")
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());
}
}
}
}
ํ๋์ ์ ์คํํธ ์์ ์๋ ์ด๋๋ฐ์ด์ค๋ฅผ LogAspect, TxAspect ์ ์คํํธ๋ก ๊ฐ๊ฐ ๋ถ๋ฆฌํ๋ค.
๊ทธ๋ฆฌ๊ณ ๊ฐ ์ ์คํํธ์ @Order ์ ๋ ธํ ์ด์ ์ ํตํด ์คํ ์์๋ฅผ ์ ์ฉํ๋ค. ์ฐธ๊ณ ๋ก ์ซ์๊ฐ ์์์๋ก ๋จผ์ ์คํ๋๋ค.
์คํ ๊ฒฐ๊ณผ
[ํธ๋์ญ์
์์] void hello.aop.order.OrderService.orderItem(String)
[log] 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)
์ด๋๋ฐ์ด์ค ์ข ๋ฅ
@Slf4j
@Aspect
public class AspectV6Advice {
@Around("hello.aop.order.aop.Pointcuts.orderAndService()")
public Object doTransaction(ProceedingJoinPoint joinPoint) throws Throwable {
try {
//@Before
log.info("[ํธ๋์ญ์
์์] {}", joinPoint.getSignature());
Object result = joinPoint.proceed();
//@AfterReturning
log.info("[ํธ๋์ญ์
์ปค๋ฐ] {}", joinPoint.getSignature());
return result;
} catch (Exception e) {
//@AfterThrowing
log.info("[ํธ๋์ญ์
๋กค๋ฐฑ] {}", joinPoint.getSignature());
throw e;
} finally {
//@After
log.info("[๋ฆฌ์์ค ๋ฆด๋ฆฌ์ฆ] {}", joinPoint.getSignature());
}
}
@Before("hello.aop.order.aop.Pointcuts.orderAndService()")
public void doBefore(JoinPoint joinPoint) {
log.info("[before] {}", joinPoint.getSignature());
}
@AfterReturning(value = "hello.aop.order.aop.Pointcuts.orderAndService()", returning = "result")
public void doReturn(JoinPoint joinPoint, Object result) {
log.info("[return] {} return={}", joinPoint.getSignature(), result);
}
@AfterThrowing(value = "hello.aop.order.aop.Pointcuts.orderAndService()", throwing = "ex")
public void doThrowing(JoinPoint joinPoint, Exception ex) {
log.info("[ex] {} message={}", ex);
}
@After(value = "hello.aop.order.aop.Pointcuts.orderAndService()")
public void doAfter(JoinPoint joinPoint) {
log.info("[after] {}", joinPoint.getSignature());
}
}
์ด๋๋ฐ์ด์ค ์ข ๋ฅ
@Before
- ์กฐ์ธ ํฌ์ธํธ ์คํ ์
@AfterReturning
- ๋ฉ์๋ ์คํ์ด ์ ์์ ์ผ๋ก ๋ฐํ๋ ๋ ์คํ
@AfterThrowing
- ๋ฉ์๋ ์คํ์ด ์์ธ๋ฅผ ๋์ ธ์ ์ข ๋ฃ๋ ๋ ์คํ
@After
- ๋ฉ์๋ ์คํ์ด ์ข ๋ฃ๋๋ฉด ์คํ๋๋ค. (finally๋ฅผ ์๊ฐํ๋ฉด ๋๋ค.)
- ์ ์ ๋ฐ ์์ธ ๋ฐํ ์กฐ๊ฑด์ ๋ชจ๋ ์ฒ๋ฆฌํ๋ค.
-
์ผ๋ฐ์ ์ผ๋ก ๋ฆฌ์์ค๋ฅผ ํด์ ํ๋ ๋ฐ ์ฌ์ฉํ๋ค.
@Around
- ๋ฉ์๋์ ์คํ์ ์ฃผ๋ณ์์ ์คํ๋๋ค.
- ๋ฉ์๋ ์คํ ์ ํ์ ์์ ์ ์ํํ๋ค. ๊ฐ์ฅ ๊ฐ๋ ฅํ ์ด๋๋ฐ์ด์ค
- ์ด๋๋ฐ์ด์ค์ ์ฒซ ๋ฒ์งธ ํ๋ผ๋ฏธํฐ๋ ProceedingJoinPoint๋ฅผ ์ฌ์ฉํด์ผ ํ๋ค.
- proceed()๋ฅผ ํตํด ๋์์ ์คํํ๋ค.
- proceed()๋ฅผ ์ฌ๋ฌ๋ฒ ์คํํ ์๋ ์์(์ฌ์๋)
์ฐธ๊ณ ์ ๋ณด ํ๋
๋ชจ๋ ์ด๋๋ฐ์ด์ค๋ org.aspectj.lang.JoinPoint๋ฅผ ์ฒซ๋ฒ์งธ ํ๋ผ๋ฏธํฐ์ ์ฌ์ฉํ ์ ์๋ค. (์๋ตํด๋ ๋๋ค.)
๋จ @Around๋ ProceedingJoinPoint์ ์ฌ์ฉํด์ผ ํ๋ค.
์ฐธ๊ณ ๋ก ProceedingJoinPoint๋ org.aspectj.lang.JoinPoint์ ํ์ ํ์ ์ด๋ค.
JoinPoint ์ธํฐํ์ด์ค์ ์ฃผ์ ๊ธฐ๋ฅ
- getArgs(): ๋ฉ์๋ ์ธ์๋ฅผ ๋ฐํํฉ๋๋ค
- getThis(): ํ๋ก์ ๊ฐ์ฒด๋ฅผ ๋ฐํํฉ๋๋ค.
- getTarget(): ๋์ ๊ฐ์ฒด๋ฅผ ๋ฐํํฉ๋๋ค.
- getSignature(): ์กฐ์ธ๋๋ ๋ฉ์๋์ ๋ํ ์ค๋ช ์ ๋ฐํํฉ๋๋ค.
- toString(): ์กฐ์ธ๋๋ ๋ฐฉ๋ฒ์ ๋ํ ์ ์ฉํ ์ค๋ช ์ ์ธ์ํฉ๋๋ค.
ProceedingJoinPoint ์ธํฐํ์ด์ค์ ์ฃผ์ ๊ธฐ๋ฅ
- proceed(): ๋ค์ ์ด๋๋ฐ์ด์ค๋ ํ์ผ์ ํธ์ถํ๋ค.
์คํํ๋ฆ

์์
- ์คํ๋ง์ 5.2.7 ๋ฒ์ ๋ถํฐ ๋์ผํ @Aspect์์์ ๋์ผํ ์กฐ์ธํฌ์ธํธ์ ์ฐ์ ์์๋ฅผ ์ ํ๋ค.
- ์คํ ์์: @Around, @Before, @After, @AfterReturning, @AfterThrowing
- ์ด๋๋ฐ์ด์ค๊ฐ ์ ์ฉ๋๋ ์์๋ ์ด๋ ๊ฒ ์ ์ฉ๋์ง๋ง, ํธ์ถ ์์์ ๋ฆฌํด ์์๋ ๋ฐ๋๋ผ๋ ์ ์ ์์๋์.
- ๋ฌผ๋ก @Aspect์์ ๋์ผํ ์ข ๋ฅ์ ์ด๋๋ฐ์ด์ค๊ฐ 2๊ฐ ์์ผ๋ฉด ์์๊ฐ ๋ณด์ฅ๋์ง ์๋๋ค.
- ์ด ๊ฒฝ์ฐ ์์ ๋ฐฐ์ด ๊ฒ ์ฒ๋ผ @Aspect๋ฅผ ๋ถ๋ฆฌํ๊ณ @Order๋ฅผ ์ ์ฉํ์.
'Spring > AOP' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
ํฌ์ธํธ์ปท ์ง์์ (2) | 2024.11.14 |
---|---|
์คํ๋ง AOP ๊ฐ๋ (0) | 2024.11.12 |
@Aspect AOP (0) | 2024.11.12 |
๋น ํ์ฒ๋ฆฌ๊ธฐ (0) | 2024.11.12 |
ํฌ์ธํธ์ปท, ์ด๋๋ฐ์ด์ค, ์ด๋๋ฐ์ด์ (0) | 2024.11.11 |