AOP๋ 'Aspect Oriented Programming'์ ์ฝ์๋ก, ๊ด์ ์งํฅ ํ๋ก๊ทธ๋๋ฐ
์ด๋ผ๊ณ ๋ ํ๋ค. ๊ด์ ์งํฅ์ ์ด๋ค ๋ก์ง์ ํต์ฌ์ ์ธ ๊ด์
๊ณผ ๋ถ๊ฐ์ ์ธ ๊ด์
์ผ๋ก ๋๋์ด์ ๋ณด๊ณ , ๊ทธ ๊ด์ ์ ๊ธฐ์ค์ผ๋ก ๋ชจ๋ํ
ํ๋ ๊ฒ์ ๋งํ๋ค.
*๋ชจ๋ํ : ์ด๋ค ๊ณตํต๋ ๋ก์ง์ด๋ ๊ธฐ๋ฅ์ ํ๋์ ๋จ์๋ก ๋ฌถ๋ ๊ฒ
๋ถ๊ฐ๊ธฐ๋ฅ์ '์ธ์ ์ํํ ๊ฑด์ง' ๊ฒฐ์ ํ๋ค. ์๋ฅผ ๋ค๋ฉด ํต์ฌ๊ธฐ๋ฅ์ด ์คํ๋ ์ ์ด๋ ํ๊ฐ ๋ ์ ์๊ณ , ์ ยทํ ์ ๋ถ๊ฐ ๋ ์ ์๋ค. ๋, ํต์ฌ๊ธฐ๋ฅ ์ํ ์ฑ๊ณต ์ฌ๋ถ์ ๋ฐ๋ผ ๋์ํ ์ง๋ ๊ฒฐ์ ํ ์ ์๊ณ , ํต์ฌ๊ธฐ๋ฅ ์ํ์ ๊ฒฐ๊ณผ๋ก ๋ฐํ๋ ๊ฒฐ๊ณผ๋ฌผ์ ์ฌ์ฉํ ์ง๋ฅผ ๊ฒฐ์ ํ ์๋ ์๋ค.
@Around
: 'ํต์ฌ๊ธฐ๋ฅ' ์ํ ์ ๊ณผ ํ (@Before + @After)@Before
: 'ํต์ฌ๊ธฐ๋ฅ' ํธ์ถ ์ @After
: 'ํต์ฌ๊ธฐ๋ฅ' ์ํ ์ฑ๊ณต/์คํจ ์ฌ๋ถ์ ์๊ด์์ด ์ธ์ ๋ ๋์ @AfterReturning
: 'ํต์ฌ๊ธฐ๋ฅ' ํธ์ถ ์ฑ๊ณต ์ (ํจ์์ Return ๊ฐ ์ฌ์ฉ ๊ฐ๋ฅ)@AfterThrowing
: 'ํต์ฌ๊ธฐ๋ฅ' ํธ์ถ ์คํจ ์. ์ฆ, ์์ธ (Exception) ๊ฐ ๋ฐ์ํ ๊ฒฝ์ฐ๋ง ๋์pointcut = ์ง์ . ๋ถ๊ฐ๊ธฐ๋ฅ์ ๋ง๋ ํ, ํต์ฌ๊ธฐ๋ฅ์ ์ด๋์ ๋ถ์ผ์ง(์ํํ ์ง) ๊ฒฐ์ ํ๋ค.
?
๋ ์๋ต ๊ฐ๋ฅํ๋ค.
execution(modifiers-pattern? return-type-pattern declaring-type-pattern? method-name-pattern(param-pattern) throws-pattern?)
modifiers-pattern
return-type-pattern
declaring-type-pattern
method-name-pattern(param-pattern)
@Around("execution(public * com.sparta.myselectshop.controller..*(..))")
public Object execute(ProceedingJoinPoint joinPoint) throws Throwable { ... }
@Component
@Aspect
public class Aspect {
// ํจํค์ง์ ๋ชจ๋ ํด๋์ค์ ์ ์ฉ + ์ธ์๊ฐ ๋ช ๊ฐ์ธ์ง ์๊ด์์
@Pointcut("execution(* com.sparta.myselectshop.controller.*.*(..))")
private void forAllController() {}
// ๋ฐํ ํ์
String์ธ + ๋ชจ๋ ํด๋์ค + ์ธ์ ์์
@Pointcut("execution(String com.sparta.myselectshop.controller.*.*())")
private void forAllViewController() {}
/* @Pointcut์ ํธ์ถํ ๋๋ ๋ฉ์๋ ๋ช
์ผ๋ก */
// ๋ชจ๋ ์ปจํธ๋กค๋ฌ์ด๋ฉด์ && view ์ปจํธ๋กค๋ฌ๋ ์๋(!)
@Around("forAllContorller() && !forAllViewController()")
public void saveRestApiLog() {
...
}
// ๋ชจ๋ ์ปจํธ๋กค๋ฌ๋ฅผ ํธ์ถ
@Around("forAllContorller()")
public void saveAllApiLog() {
...
}
}
@Slf4j(topic = "UseTimeAop")
@Aspect
@Component
@RequiredArgsConstructor
public class UseTimeAop {
/* ์์ฑ์ ์ฃผ์
์๋ต */
// ProductController + ์ธ์ ์๊ด ์์
@Pointcut("execution(* com.sparta.myselectshop.controller.ProductController.*(..))")
private void product() {}
// FolderController + ์ธ์ ์๊ด ์์
@Pointcut("execution(* com.sparta.myselectshop.controller.FolderController.*(..))")
private void folder() {}
// NaverApiController + ์ธ์ ์๊ด ์์
@Pointcut("execution(* com.sparta.myselectshop.naver.controller.NaverApiController.*(..))")
private void naver() {}
// product ํน์ folder ํน์ naver api ์ปจํธ๋กค๋ฌ์
// ์ ๋ค๋ก(@Around) execute() ์คํ
@Around("product() || folder() || naver()")
public Object execute(ProceedingJoinPoint joinPoint) throws Throwable {
// ์ธก์ ์์ ์๊ฐ
// ...
execute()
๋ด๋ถ์์๋ ํต์ฌ๊ธฐ๋ฅ์ ์คํ ํ โ ๋ถ๊ฐ๊ธฐ๋ฅ์ ์คํํ๋ค.
@Around("product() || folder() || naver()")
public Object execute(ProceedingJoinPoint joinPoint) throws Throwable {
// ์ธก์ ์์ ์๊ฐ
long startTime = System.currentTimeMillis();
try {
// ํต์ฌ๊ธฐ๋ฅ ์ํ
Object output = joinPoint.proceed();
return output;
} finally {
// ....
DispatcherServlet
๊ณผ ProductController
์
์ฅ์์๋ ๋ณํ๊ฐ ์ ํ์๋ค.joinPoint.proceed()
์ ์ํด์ ์๋ ํธ์ถํ๋ ค๊ณ ํ๋ ํจ์, ์ธ์(argument) ๊ฐ ์ ๋ฌ๋๋ค.createProduct(requestDto);