๐ AOP๋?
Aspect-Oriented Programming, ๊ด์ ์งํฅ ํ๋ก๊ทธ๋๋ฐ
์์ค ์ฝ๋์ ๋น์ฆ๋์ค ๋ก์ง๊ณผ ๋ถ๊ฐ์ ์ธ ๊ณตํต ๊ด์ฌ์ฌ๋ฅผ ๋ถ๋ฆฌํ์ฌ, ๊ด์ ์ ๊ธฐ์ค์ผ๋ก ๊ฐ๊ฐ ๋ชจ๋ํํ์ฌ ์ฝ๋์ ๋ชจ๋์ฑ๊ณผ ๊ฐ๋ ์ฑ์ ํฅ์์ํค๋ ํ๋ก๊ทธ๋๋ฐ ํจ๋ฌ๋ค์.
* ’๊ด์ ’์ด๋ผ๋ ๋ง์ด ๋๋ฌด ์ด์ํด์ ์์๋ดค๋๋, ‘์ด๋ณด ์น ๊ฐ๋ฐ์๋ฅผ ์ํ ์คํ๋ง 5 ํ๋ก๊ทธ๋๋ฐ ์ ๋ฌธ 158p’์์ ‘๊ด์ ’์ด๋ผ๋ ๋ง ๋์ ‘๊ธฐ๋ฅ’ ๋ด์ง ‘๊ด์ฌ’์ด๋ผ๊ณ ํํํ๋ ๊ฒ์ด ๋ ์๋ง๋ค๊ณ ํ๋ค.
* ๋ชจ๋ํ: ์ด๋ค ๊ณตํต๋ ๋ก์ง์ด๋ ๊ธฐ๋ฅ์ ํ๋์ ๋จ์๋ก ๋ฌถ๋ ๊ฒ
์ฆ, ์ฌ๋ฌ ๊ฐ์ฒด์ ๊ณตํต์ผ๋ก ์ ์ฉํ ์ ์๋ ๊ธฐ๋ฅ์ ๋ถ๋ฆฌํด์ Aspect๋ก ๋ชจ๋ํํ์ฌ ์ฌ์ฌ์ฉ์ฑ์ ๋์ฌ์ฃผ๋ ๊ธฐ๋ฒ์ด๋ค. ํต์ฌ ๊ธฐ๋ฅ๊ณผ ๊ณตํต ๊ธฐ๋ฅ(ํฉ์ด์ง ๊ด์ฌ์ฌ)์ ๊ตฌํ์ ๋ถ๋ฆฌํจ์ผ๋ก์จ ํต์ฌ ๊ธฐ๋ฅ์ ๊ตฌํํ ์ฝ๋์ ์์ ์์ด ๊ณตํต ๊ธฐ๋ฅ์ ์ฝ์ ํ ์ ์๊ฒ ๋ง๋ค์ด ์ค๋ค.
- ํฉ์ด์ง ๊ด์ฌ์ฌ(Crosscutting Concerns): ์์ค ์ฝ๋ ์ ๋ค๋ฅธ ๋ถ๋ถ์ ๊ณ์ ๋ฐ๋ณตํด์ ์ฌ์ฉํ๋ ์ฝ๋๋ค
ํต์ฌ ๊ธฐ๋ฅ์ ๊ณตํต ๊ธฐ๋ฅ์ ์ฝ์ ํ๋ ๋ฐฉ๋ฒ
1. ์ปดํ์ผ ์์ ์ ์ฝ๋์ ๊ณตํต ๊ธฐ๋ฅ์ ์ฝ์ ํ๋ ๋ฐฉ๋ฒ
: AOP ๊ฐ๋ฐ ๋๊ตฌ๊ฐ ์์ค ์ฝ๋๋ฅผ ์ปดํ์ผ ํ๊ธฐ ์ ์ ๊ณตํต ๊ตฌํ ์ฝ๋๋ฅผ ์์ค์ ์ฝ์ ํ๋ ๋ฐฉ์์ผ๋ก ๋์
2. ํด๋์ค ๋ก๋ฉ ์์ ์ ๋ฐ์ดํธ ์ฝ๋์ ๊ณตํต ๊ธฐ๋ฅ์ ์ฝ์ ํ๋ ๋ฐฉ๋ฒ
: ํด๋์ค๋ฅผ ๋ก๋ฉํ ๋ ๋ฐ์ดํธ ์ฝ๋์ ๊ณตํต ๊ธฐ๋ฅ์ ํด๋์ค์ ์ฝ์ ํ๋ ๋ฐฉ์์ผ๋ก ๋์
3. ๋ฐํ์์ ํ๋ก์ ๊ฐ์ฒด๋ฅผ ์์ฑํด์ ๊ณตํต ๊ธฐ๋ฅ์ ์ฝ์ ํ๋ ๋ฐฉ๋ฒ
: ์คํ๋ง์ด ์ ๊ณตํ๋ ๋ฐฉ์
1,2๋ฒ์ ์คํ๋ง AOP์์ ์ง์ํ์ง ์์ผ๋ฉฐ, AspectJ์ ๊ฐ์ด aop ์ ์ฉ ๋๊ตฌ๋ฅผ ์ฌ์ฉํด์ ์ ์ฉํ ์ ์๋ค.
๐ฟ Spring AOP
Spring AOP๋ “Aspect ํด๋์ค์ Target Object๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ํ๋ก์ ๊ฐ์ฒด๋ฅผ ์๋์ผ๋ก ์์ฑ”ํ์ฌ ์๋์ ๋์ ๊ฐ์ฒด๋ฅผ ๊ฐ์ธ๊ณ , ๋ฉ์๋ ํธ์ถ ์ ํ๋ก์๊ฐ ๊ฐ๋ก์ฑ์ ๋ถ๊ฐ์ ์ธ ๋ก์ง์ ์คํํ๋ค. (๊ด๋ฆฌ๋ ์์์ ํด์ค)
→ ์ธํฐํ์ด์ค๊ฐ ์๋ค๋ฉด, ์ธํฐํ์ด์ค ๊ธฐ๋ฐ์ ํ๋ก์ ๊ฐ์ฒด๋ฅผ ์์ฑํด์ค๋ค.
→ ์ธํฐํ์ด์ค๊ฐ ์๋ค๋ฉด, ๊ตฌ์ฒด ํด๋์ค ๊ธฐ๋ฐ์ ํ๋ก์ ๊ฐ์ฒด๋ฅผ ์์ฑํด์ค๋ค.
⇒ ๊ณตํต ๊ธฐ๋ฅ์ ๊ตฌํํ ํด๋์ค๋ง ์๋ง๊ฒ ๊ตฌํํ๋ฉด ๋๊ณ , ํ๋ก์ ํด๋์ค๋ ์ง์ ๊ตฌํํ ํ์๊ฐ ์๋ค.
๊ทธ์ , ๊ณตํต๊ธฐ๋ฅ์ ๊ตฌํํ ํด๋์ค๋ฅผ ๋ณ๋๋ก ์์ฑํ ๋ค, AOP์ Aspect๋ก ๋ฑ๋ก๋ง ํ๋ฉด ๋๋ค.
์คํ๋ง์ ํ๋ก์๋ฅผ ์ด์ฉํด์ ๋ฉ์๋ ํธ์ถ ์์ ์ Aspect๋ฅผ ์ ์ฉํ๋ค.
- Proxy ๊ฐ์ฒด: ํต์ฌ ๊ธฐ๋ฅ์ ์คํ์ ๋ค๋ฅธ ๊ฐ์ฒด์ ์์ํ๊ณ , ๋ถ๊ฐ์ ์ธ ๊ธฐ๋ฅ์ ์ ๊ณตํ๋ ๊ฐ์ฒด (๋์ ๊ฐ์ฒด์ ๋๋ฆฌ์ธ. ๋์ ๊ฐ์ฒด์ ๋์์ ํ์ฅํ๊ฑฐ๋ ๋ณ๊ฒฝ)
- proxy ๊ฐ์ฒด: ์ ๊ทผ ์ ์ด ๊ด์ ์ ์ด์ .
- decorator ๊ฐ์ฒด: ๊ธฐ๋ฅ ์ถ๊ฐ์ ํ์ฅ์ ์ด์
- Target ๊ฐ์ฒด: ์ค์ ํต์ฌ ๊ธฐ๋ฅ์ ์คํํ๋ ๊ฐ์ฒด
๐ ์ฃผ์ ๊ฐ๋
- Aspect: ๊ณตํต์ ์ผ๋ก ์ ์ฉ๋๋ ๋ถ๊ฐ์ ์ธ ๊ธฐ๋ฅ(์: ๋ก๊น , ๊ถํ ๊ฒ์ฌ). ์ค์ ๋ก ๊ตฌํ๋ ์ฝ๋
- Advice: ์ธ์ ๊ณตํต ๊ด์ฌ ๋ก์ง์ ํต์ฌ ๋ก์ง์ ์ ์ฉํ ์ง๋ฅผ ์ ์
- Before: ๋ฉ์๋ ์คํ ์ ์ ์คํ
- After: ๋ฉ์๋ ์คํ ํ์ ์คํ
- AfterReturning: ๋ฉ์๋๊ฐ ์ ์์ ์ผ๋ก ์ข ๋ฃ๋ ํ ์คํ
- AfterThrowing: ๋ฉ์๋์์ ์์ธ๊ฐ ๋ฐ์ํ ํ ์คํ
- Around: ๋ฉ์๋ ์คํ ์ ํ์ ์คํ (๊ฐ์ฅ ๋๋ฆฌ ์ฌ์ฉ๋จ)
- ๋์ ๊ฐ์ฒด์ ๋ฉ์๋๋ฅผ ์คํํ๊ธฐ ์ /ํ, ์ต์ ์ ๋ฐ์ ์์ ๋ฑ ๋ค์ํ ์์ ์ ์ํ๋ ๊ธฐ๋ฅ์ ์ฝ์ ๊ฐ๋ฅ
- Join Point: Advice๊ฐ ์ ์ฉ ๊ฐ๋ฅํ ์ง์ (์: ๋ฉ์๋ ํธ์ถ, ํ๋ ์ ๊ทผ ๋ฑ)
- ์คํ๋ง์ ํ๋ก์๋ฅผ ์ด์ฉํด์ AOP๋ฅผ ๊ตฌํํ๊ธฐ ๋๋ฌธ์ ๋ฉ์๋ ํธ์ถ์ ๋ํ Join point๋ง ์ง์
- AspectJ๋ ๋ฐ์ดํธ์ฝ๋ ๋ ๋ฒจ์์ ๋์ํ๋ ์์ ํ aop ํ๋ ์์ํฌ๋ก, join point์ ๋ฒ์๊ฐ ํจ์ฌ ๋์
- Pointcut: Join Point๋ฅผ ํํฐ๋งํ๋ ํํ์. ์ค์ advice๊ฐ ์ ์ฉ๋๋ join point๋ฅผ ๋ํ๋
- Weaving: Advice๋ฅผ ํต์ฌ ๋ก์ง ์ฝ๋์ ์ ์ฉํ๋ ๊ฒ
execution ๋ช ์์
: Advice๋ฅผ ์ ์ฉํ ๋ฉ์๋๋ฅผ ์ง์ ํ ๋ ์ฌ์ฉ
@Pointcut("execution(* LuckyVicky.backend..*.controller.*.*(..)) || "
+ "execution(* LuckyVicky.backend..*.service.*.*(..)) ||"
+ " execution(* LuckyVicky.backend..*.repository.*.*(..))")
public void applicationLayerPointcut() {
}
execution(์์์ดํจํด ? ๋ฆฌํดํ์ ํจํด ํด๋์ค์ด๋ฆํจํด?๋ฉ์๋์ด๋ฆํจํด(ํ๋ผ๋ฏธํฐํจํด)
- ์์์ดํจํด: ์๋ต ๊ฐ๋ฅ. public, protected๊ฐ ์ด. spring์์๋ public ๋ฉ์๋์๋ง ์ ์ฉ ๊ฐ๋ฅ.
- ๋ฆฌํดํ์ ํจํด: ๋ฆฌํดํ์ ๋ช ์.
- ํด๋์ค ์ด๋ฆํจํด, ๋ฉ์๋ ์ด๋ฆ ํจํด: ํด๋์ค ์ด๋ฆ ๋ฐ ๋ฉ์๋ ์ด๋ฆ์ ํจํด์ผ๋ก ๋ช ์
- ํ๋ผ๋ฏธํฐํจํด: ๋งค์นญ๋ ํ๋ผ๋ฏธํฐ์ ๋ํด ๋ช ์
@Pointcut ์ ๋ ธํ ์ด์ ์ด ์๋ @Around ์ ๋ ธํ ์ด์ ์ execution ๋ช ์์๋ฅผ ์ง์ ์ง์ ํ ์๋ ์๋ค.
@Around("execution(* LuckyVicky.backend..*.controller.*.*(..)) || "
+ "execution(* LuckyVicky.backend..*.service.*.*(..)) ||"
+ " execution(* LuckyVicky.backend..*.repository.*.*(..))")
public Object logError(ProceedingJoinPoint joinPoint) throws Throwable {
๋ง์ฝ, ๊ฐ์ Pointcut์ ์ฌ๋ฌ Advice๊ฐ ํจ๊ป ์ฌ์ฉํ๋ค๋ฉด, ๊ณตํต pointcut์ ์ฌ์ฌ์ฉํ ์๋ ์๋ค.
์๋ ์ฝ๋ ์ฒ๋ผ pointcut ์ ๋ ธํ ์ด์ ์ด ๋ถ์ ๋ฉ์๋๋ฅผ public์ผ๋ก ์ ์ํด์ฃผ๋ฉด ๋๋ค!
@Aspect
@Component
public class ErrorLoggingAspect {
private static final Logger logger = LoggerFactory.getLogger(ErrorLoggingAspect.class);
@Pointcut("execution(* LuckyVicky.backend..*.controller.*.*(..)) || "
+ "execution(* LuckyVicky.backend..*.service.*.*(..)) ||"
+ " execution(* LuckyVicky.backend..*.repository.*.*(..))")
public void applicationLayerPointcut() {
}
// public์ด๋ผ ๋ค๋ฅธ ํด๋์ค์ ์ํ Advice์์๋ ํด๋น pointcut ์ฌ์ฉํ ์ ์์!
@AfterThrowing(pointcut = "applicationLayerPointcut()", throwing = "exception")
public void logError(JoinPoint joinPoint, Throwable exception) {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
String methodName = signature.getMethod().getName();
String className = joinPoint.getTarget().getClass().getSimpleName();
Object[] args = joinPoint.getArgs();
logger.error("!! [ERROR] Exception in {}.{}() with arguments: {}", className, methodName, args);
logger.error("Exception: {}", exception.getMessage(), exception);
}
}
๐ Aspect๊ฐ ์ฌ๋ฌ๊ฐ๋ผ๋ฉด?
์ด๋ค Aspect๊ฐ ๋จผ์ ์ ์ฉ๋ ์ง๋ ์คํ๋ง ํ๋ ์์ํฌ๋ ์๋ฐ ๋ฒ์ ์ ๋ฐ๋ผ ๋ฌ๋ผ์ง ์ ์๊ธฐ์ ์ ์ฉ ์์๊ฐ ์ค์ํ๋ค๋ฉด, ์ง์ ์์๋ฅผ ์ง์ ํด์ผ ํ๋ค. ์ด๋ @Order๋ฅผ ์ฌ์ฉํ ์ ์๋ค.
- @Order(_) ๊ฐ์ด ์์ผ๋ฉด ๋จผ์ ์ ์ฉํ๊ณ , ํฌ๋ฉด ๋์ค์ ์ ์ฉํ๋ค.
๐ @Aspect์ ์ปดํฌ๋ํธ ์ค์บ
@Aspect๊ฐ ์ปดํฌ๋ํธ ์ค์บ ๋์์ด๊ธฐ์ @Aspect๊ฐ ๋ถ๊ธฐ๋ง ํ๋ฉด, ํด๋น ํด๋์ค๋ ์ปจํ ์ด๋๊ฐ ๋น์ผ๋ก ๋ฑ๋กํด์ค๋ค.
๊ทธ๋์, Spring AOP๋ฅผ ์ฌ์ฉํ ๋ @Aspect ์ ๋ ธํ ์ด์ ์ ๋ถ์ธ ํด๋์ค๋ ์๋์ผ๋ก ์ปดํฌ๋ํธ ์ค์บ ๋์์ด ๋์ง๋ง, @EnableAspectJAutoProxy ์ ๋ ธํ ์ด์ ์ ํตํด AOP ์ค์ ์ด ํ์ฑํ๊ฐ ๋ ๊ฒฝ์ฐ์ ์๋์ด ๋๋ค.
๋ค๋ง, Spring Boot์์๋ ๊ธฐ๋ณธ์ ์ผ๋ก ํ์ฑํ๋์ด ์๊ธฐ์ ๋ฐ๋ก ์ ๊ฒฝ ์จ์ฃผ์ง ์์๋ ๋๋ค. ํ์ง๋ง, Spring Boot๋ฅผ ์ฌ์ฉํ์ง ์๋ ์์ Spring Framework ํ๋ก์ ํธ์์๋ @EnableAspectJAutoProxy๋ฅผ ๋ช ์์ ์ผ๋ก ์ ์ธํด์ผ AOP ๊ธฐ๋ฅ์ด ํ์ฑํ๋๋ค.
@EnableAspectJAutoProxy ์ ๋ ธํ ์ด์
- Spring AOP๋ฅผ ํ์ฑํํ๋ ์ ๋ ธํ ์ด์
- @Aspect ํด๋์ค๊ฐ ์ค์บ๋๊ณ ํ๋ก์๊ฐ ์์ฑ
@Aspect๋ง์ผ๋ก๋ Spring AOP๊ฐ ํ์ฑํ๋๋ฉด ํด๋น ํด๋์ค๊ฐ ์ปดํฌ๋ํธ ์ค์บ์ ๋์์ด ๋์ง๋ง, ๋ช ์์ ์ผ๋ก ๋น ๋ฑ๋ก์ ๋ณด์ฅํ๊ฑฐ๋ ํผ๋์ ์ค์ด๊ธฐ ์ํด @Component๋ฅผ ์ถ๊ฐํ๋ ๊ฒ์ด ์ผ๋ฐ์ ์ด๋ผ๊ณ ํ๋ค.
์ด์ ๋ํ ์ฅ์ ์ด..
1. AOP ์ค์ ์ด ๋นํ์ฑํ๋์ด๋ ํด๋น ํด๋์ค๊ฐ ์คํ๋ง ๋น์ผ๋ก ๋ฑ๋ก๋๊ณ , AOP๊ฐ ์๋, ๋ค๋ฅธ ๋ฐฉ์์ผ๋ก๋ ์ด ํด๋์ค์ ๊ธฐ๋ฅ์ ํ์ฉํ ์ ์๋ค.
2. @Aspect ํด๋์ค๋ ์ผ๋ฐ์ ์ธ ์คํ๋ง ๋น์ฒ๋ผ ์ปดํฌ๋ํธ ์ค์บ ๋์์์ ๋ช ํํ ํ๊ธฐ ์ํด @Component๋ฅผ ํจ๊ป ์ฌ์ฉํ๋ ๊ฒ์ด ๊ด๋ก๋ผ๊ณ ํ๋ค.
* @Controller, @Service, @Repository, @Configuration์ ๋ชจ๋ @Component์ ํน์ ์ ๋ ธํ ์ด์ ์ด๋ค. ๊ทธ๋์ @Component๋ฅผ ํจ๊ป ์ฌ์ฉํ๋ฉด ๋ ๋ช ์์ ์ผ๋ก ์ค์บ ๋์์์ ๋ณด์ผ ์ ์๋ค.
๐ AOP ์ฌ์ฉ ์ฌ๋ก
- ๋ก๊น
(Logging)
๋ฉ์๋ ํธ์ถ ๋ฐ ์๋ต ์๊ฐ์ ๊ธฐ๋กํ๊ฑฐ๋, ์์ธ๊ฐ ๋ฐ์ํ์ ๋ ํด๋น ์ ๋ณด๋ฅผ ๋ก๊ทธ๋ก ๋จ๊ธฐ๋ ๋ฐ ํ์ฉ๋๋ค. ์ด๋ฅผ ํตํด ๋๋ฒ๊น ์ด๋ ๋ฌธ์ ๋ถ์ ์ ์ ์ฉํ ์ ๋ณด๋ฅผ ์์ฝ๊ฒ ์์งํ ์ ์๋ค. - ํธ๋์ญ์
๊ด๋ฆฌ(Transaction Management)
๋ฐ์ดํฐ๋ฒ ์ด์ค ํธ๋์ญ์ ์ ์์, ์ปค๋ฐ, ๋กค๋ฐฑ๊ณผ ๊ฐ์ ์ฒ๋ฆฌ๋ฅผ ๋ฉ์๋ ์คํ ์ ํ์ ์๋์ผ๋ก ์ ์ฉํ ์ ์๋ค. ์ด๋ฅผ ํตํด ์ฝ๋ ์ค๋ณต์ ์ค์ด๊ณ ํธ๋์ญ์ ๊ด๋ฆฌ ๋ก์ง์ ์ผ๊ด๋๊ฒ ์ ์งํ ์ ์๋ค. - ๊ถํ ๊ฒ์ฌ(Authorization)
ํน์ ๋ฉ์๋๊ฐ ํธ์ถ๋๊ธฐ ์ ์ ์ฌ์ฉ์ ๊ถํ์ ํ์ธํ์ฌ, ๊ถํ์ด ์๋ ์ฌ์ฉ์์ ์ ๊ทผ์ ์ฐจ๋จํ๋ ๋ก์ง์ ๋ถ๋ฆฌํ์ฌ ๊ตฌํํ ์ ์๋ค. ์ด๋ฅผ ํตํด ๋ณด์ ๋ก์ง์ ์ค์ ์ง์คํํ ์ ์๋ค. - ์ฑ๋ฅ ๋ชจ๋ํฐ๋ง(Performance Monitoring)
๋ฉ์๋์ ์คํ ์๊ฐ์ ์ธก์ ํ์ฌ ์ฑ๋ฅ ๋ณ๋ชฉ ์ง์ ์ ํ์ ํ๊ฑฐ๋ ์ต์ ํ๊ฐ ํ์ํ ๋ถ๋ถ์ ์๋ณํ ์ ์๋ค. ์ฃผ๋ก ์ ํ๋ฆฌ์ผ์ด์ ์ ์ฑ๋ฅ์ ๋ชจ๋ํฐ๋งํ๊ณ ๊ฐ์ ํ๋ ๋ฐ ์ฌ์ฉ๋๋ค.
์ด๋ฌํ ์ฌ๋ก๋ค์ ์ ํ๋ฆฌ์ผ์ด์ ์ ํต์ฌ ๋ก์ง์ ์ํฅ์ ์ฃผ์ง ์์ผ๋ฉด์๋, ๋ถ๊ฐ์ ์ธ ๋ก์ง์ ๊น๋ํ๊ฒ ๊ด๋ฆฌํ ์ ์๋๋ก ๋์์ค๋ค. AOP๋ฅผ ์ ์ ํ ํ์ฉํ๋ฉด ์ฝ๋์ ๊ฐ๋ ์ฑ๊ณผ ์ฌ์ฌ์ฉ์ฑ์ ํฌ๊ฒ ํฅ์์ํฌ ์ ์๋ค.
AOP๋ฅผ ์ด์ฉํ "๋ก๊น " ์์ ์ฝ๋๋ฅผ ๋ณด๋ ค๋ฉด ์๋ ํฌ์คํ ์ ์ฐธ๊ณ ํ์!
https://persi0815.tistory.com/118
์ฐธ๊ณ ํ๋ฉด ์ข์ ์๋ฃ
https://tecoble.techcourse.co.kr/post/2022-11-07-transaction-aop-fact-and-misconception/
'Backend > Spring AOP' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[Spring Boot] AOP๋ก ๋ก๊ทธ ํ์ผ ์์ฑ ๋ฐ S3 ์ ๋ก๋ํ๊ธฐ (0) | 2024.12.14 |
---|