AOP (Aspect-Oriented Programming)
π κ°μ
- AOPλ λ‘κΉ Β·νΈλμμ ·보μ κ°μ ν‘λ¨ κ΄μ¬μ¬λ₯Ό νκ³³(Aspect)μΌλ‘ λͺ¨μ ν΅μ¬ λΉμ¦λμ€ λ‘μ§(μ£Όμ κ΄μ¬μ¬) μμ λΆλ¦¬νλ κΈ°λ²μ΄λ€.
- Spring AOPλ νλ‘μ κΈ°λ°μΌλ‘ βλ©μλ μ€νβ μ§μ (join point)μ Adviceλ₯Ό μ½μ ν΄ λμνλ€.
- λ΄λΆ νΈμΆ(Self-invocation)Β·
final/private
λ©μλ λ± νλ‘μ νκ³λ₯Ό μ΄ν΄νκ³ μ€κ³ν΄μΌ νλ€.
κ°λ & λ°°κ²½
OOP(κ°μ²΄ μ§ν₯ νλ‘κ·Έλλ°) μμ λͺ¨λνμ ν΅μ¬ λ¨μλ ν΄λμ€μ΄μ§λ§, AOPμμ λͺ¨λνμ ν΅μ¬ λ¨μλ **Aspect(κ΄μ )**μ΄λ€.
- ν‘λ¨ κ΄μ¬μ¬(Cross-cutting concerns) : λ‘κΉ , νΈλμμ , 보μ, λͺ¨λν°λ§ λ± μ¬λ¬ λͺ¨λμ κ±Έμ³ λ°λ³΅λλ κΈ°λ₯
- μ£Όμ κ΄μ¬μ¬(Core concerns) : μλΉμ€ κ³ μ μ λΉμ¦λμ€ λ‘μ§
β λ°λ³΅ μ½λλ₯Ό κ±·μ΄λ΄κ³ , μ μ± μ μΌκ΄λκ³ μ¬μ¬μ© κ°λ₯νκ² λ§λ λ€.
- ν‘λ¨ κ΄μ¬μ¬μ μ£Όμ κ΄μ¬μ¬λ₯Ό λΆλ¦¬νμ¬ κ΄μ λ³λ‘ κ°κ° κΈ°λ₯μ λͺ¨λν ν μ μλ€.
- μ€μ μ μΆκ°νμ¬ Weaving νλ€.
κ²°λ‘
AOP λ μ€νλ§ λ§μ μ©μ΄λ μλλ©°, ν‘λ¨ κ΄μ¬μ¬(곡ν΅μ κΈ°λ₯μ μ¬λ¬ μ½λμ κ±Έμ³ λ°λ³΅μ μΌλ‘ μ μ©)λ₯Ό λͺ¨λν νλ κ°λ μ λ§νλ€.
β Spring μμλ AOPλ₯Ό ꡬννκΈ° μν΄ Proxy ν¨ν΄μ μ¬μ©νλ€.
π§© ν΅μ¬ μ©μ΄
μ©μ΄ | μ€λͺ |
---|---|
Aspect | κ³΅ν΅ κΈ°λ₯ λͺ¨λ (ex. λ‘κΉ , νΈλμμ ) |
Advice | μ€μ μνλλ μ½λ (Before/After/AfterReturning/AfterThrowing/Around) |
Join Point | AOPλ₯Ό μ μ©ν μ μλ μ§μ (ex. λ©μλ μ€ν μμ ) |
Pointcut | Adviceλ₯Ό μ μ©ν μ§μ μ§μ (Join Point 쑰건 μ μ) |
Weaving | Adviceλ₯Ό μ€μ κ°μ²΄μ μ°κ²°νλ κ³Όμ (Springμ λ°νμ Weaving) |
β AOP μ μ© λ°©μ
- νλ‘μ κΈ°λ°:
- μΈν°νμ΄μ€κ° μμΌλ©΄ JDK λμ νλ‘μ, μμΌλ©΄ CGLIB μ¬μ©
- μ§μνλ Join Point: λ©μλ μ€ν
- νλ‘μ νκ³:
- λ΄λΆ νΈμΆ(self-invocation) μ νλ‘μ μ°ν β AOP λ―Έμ μ©
final/private
λ©μλ, μμ±μ, νλ μ κ·Ό λ±μ μ μ© λΆκ°
- μ¬λ¬ Aspectμ μμλ
@Order
νΉμOrdered
λ‘ μ μ΄
Spring AOPλ λ©μλ μ€ν μμ μ Join Pointλ§ μ§μ
π§° μ£Όμ μ΄λ Έν μ΄μ
@Aspect // Aspect μ μ ν΄λμ€
@Before // λ©μλ μ€ν μ μ€ν
@AfterReturning // μ μ λ°ν ν μ€ν
@AfterThrowing // μμΈ λ°μ μ μ€ν
@After // λ©μλ μ’
λ£ ν (μ±κ³΅/μ€ν¨ 무κ΄)
@Around // λ©μλ μ€ν μ /ν λͺ¨λ μ μ΄
@Pointcut // ν¬μΈνΈμ»· μ μ
π― ν¬μΈνΈμ»· ννμ μμ
ννμ | μλ―Έ |
---|---|
execution(* com.example..*.*(..)) | λͺ¨λ λ©μλ |
execution(* *..Service.*(..)) | Service ν΄λμ€ λ΄ λͺ¨λ λ©μλ |
within(com.example.controller..*) | νΉμ ν¨ν€μ§ νμ ν΄λμ€ μ 체 |
π§ μμ
(A) κ°λ¨ λ‘κΉ
@Aspect
@Component
public class LoggingAspect {
@Before("execution(* com.example.service.*.*(..))")
public void logBefore(JoinPoint joinPoint) {
System.out.println("νΈμΆλ λ©μλ: " + joinPoint.getSignature().getName());
}
}
(B) μ€ν μκ° μΈ‘μ (@Around
)
@Aspect
@Component
public class TimingAspect {
@Around("execution(* com.example..*Service.*(..))")
public Object measure(ProceedingJoinPoint pjp) throws Throwable {
long start = System.nanoTime();
try {
return pjp.proceed();
} finally {
long elapsedMs = (System.nanoTime() - start) / 1_000_000;
System.out.println(pjp.getSignature() + " took " + elapsedMs + "ms");
}
}
}
μΆνμ νμ΅ν Filter μ Interceptor λ μ΄μ λΉμ·ν κ°λ
β 곡ν΅μ κ΄μ¬μ¬λ₯Ό λΆλ¦¬νμ¬ μ²λ¦¬νλ€λ μ μμ λΉμ·νμ§λ§, λμ μμ κ³Ό μ μ© λμμ μ°¨μ΄κ° μμ μ°Έκ³ : Spring AOP vs Filter vs Interceptor
κ΅¬λΆ | μ μ© λ μ΄μ΄ | μ£Ό μ¬μ©μ² | νΉμ§ |
---|---|---|---|
Filter | μλΈλ¦Ώ 컨ν μ΄λ | κ³΅ν΅ λ³΄μ/μΈμ½λ©/λ‘κΉ | URL λ¨μ, μ€νλ§ μΈλΆ κ³μΈ΅ |
Interceptor | μ€νλ§ MVC | 컨νΈλ‘€λ¬ μ /ν μ²λ¦¬ | νΈλ€λ¬ μ ν, λ·° λ λ μ |
AOP | μ€νλ§ λΉ λ 벨 | μλΉμ€/리ν¬μ§ν 리 λ¨ | λ©μλ μ€ν λ¨μ, νλ‘μ κΈ°λ° |
μ λͺ¨λ βκ³΅ν΅ κ΄μ¬μ¬ λΆλ¦¬β λͺ©μ μ΄μ§λ§ μ μ© μμ κ³Ό λ²μκ° λ€λ¦.
β οΈ μ£Όμν μ
- λ΄λΆ νΈμΆ: κ°μ κ°μ²΄ λ΄λΆμμ
this.method()
νΈμΆ μ AOP λ―Έμ μ© β ꡬ쑰 λΆλ¦¬/μκΈ°μ°Έμ‘° μ£Όμ (@Lazy self
) λ±μΌλ‘ μ°ν - νλ‘μ λΆκ° λμ:
final
ν΄λμ€/λ©μλ,private
λ©μλ, μμ±μ @Transactional
λ νλ‘μ κΈ°λ°μ΄λΌ λ΄λΆ νΈμΆμμ λμ μ ν¨- μ±λ₯: κ³Όλν ν¬μΈνΈμ»·/μ΄λΌμ΄λλ μ€λ²ν€λ β λ²μ μ΅μν, νμ μ§μ λ§ μ μ©
- ν
μ€νΈ:
@SpringBootTest
μμ Aspect νμ±ν, λ¨μ ν μ€νΈλ ν¬μΈνΈμ»· μ΅μνλ‘ μ¬νμ± ν보
π κ΄λ ¨
- IoC β 컨ν μ΄λκ° κ°μ²΄ μλͺ μ£ΌκΈ°/μ°κ²°μ κ΄λ¦¬
- DI β μμ‘΄μ± μ°κ²°μ μ£Όμ μΌλ‘ ν΄κ²°
- external-configuration β νκ²½/νλ‘ν κΈ°λ° μ€μ
- Spring AOP vs Filter vs Interceptor - κ° κΈ°λ₯ νΉμ± λΉκ΅