[Spring] AOP(Aspect-Oriented Programming)

혀·2022λ…„ 10μ›” 18일
0

Spring

λͺ©λ‘ 보기
10/24
post-thumbnail

πŸ“AOP와 PSA 에 μΆ”κ°€ ν•™μŠ΅ν•œ λ‚΄μš©

AOP(Aspect-Oriented Programming)

: 관점 지ν–₯ ν”„λ‘œκ·Έλž˜λ°

λ‹€μ–‘ν•œ κΈ°λŠ₯듀을 핡심과 λΆ€κ°€κΈ°λŠ₯으둜 λΆ„λ¦¬ν•˜λŠ” 것을 μ˜λ―Έν•œλ‹€.

AOP의 μ—­ν• 

πŸ’‘OOP의 λΆ€μ‘±ν•œ 뢀뢄을 λ³΄μ™„ν•œλ‹€.

☝️ OOP의 ꢁ극적인 λͺ©ν‘œλŠ” κ³΅ν†΅λœ λͺ©μ μ„ 가진 데이터와 λ©”μ„œλ“œλ₯Ό ν•˜λ‚˜μ˜ 객체둜 λ¬Άμ–΄ μ‚¬μš©ν•¨μœΌλ‘œμ¨ μ½”λ“œμ˜ μž¬μ‚¬μš©μ„±μ„ 높이고 μ€‘λ³΅μ½”λ“œλ₯Ό μ œκ±°ν•˜λŠ” 것에 μžˆλ‹€.
κ·ΈλŸ¬λ‚˜ λ‘œκΉ…, λ³΄μ•ˆ, νŠΈλžœμž­μ…˜κ³Ό 같은 λΆ€κ°€κΈ°λŠ₯은 각 λ©”μ„œλ“œλ³„λ‘œ μˆ˜ν–‰λ˜κΈ° λ•Œλ¬Έμ— μ€‘λ³΅μ½”λ“œκ°€ μƒμ„±λœλ‹€. 이런 단점을 λ³΄μ•ˆν•˜κΈ° μœ„ν•œ λ°©λ²•μœΌλ‘œ AOPλ₯Ό μ‚¬μš©ν•œλ‹€.

πŸ’‘OOPλŠ” 클래슀λ₯Ό, AOPλŠ” 관점을 λͺ¨λ“ˆν™” ν•œλ‹€.

  • OOPλŠ” 클래슀λ₯Ό λͺ¨λ“ˆν™”ν•˜κΈ° λ•Œλ¬Έμ— λ©”μ„œλ“œμ— μ€‘λ³΅λœ λΆ€κ°€ κΈ°λŠ₯의 뢄리λ₯Ό ν•  수 μ—†λ‹€.
  • AOPλŠ” 관점을 λͺ¨λ“ˆν™”ν•˜κΈ° λ•Œλ¬Έμ— OOP의 λΆ€μ‘±ν•œ λΆ€κ°€ κΈ°λŠ₯을 λΆ„λ¦¬ν•˜μ—¬ 각 λ©”μ„œλ“œμ—κ²Œ 적용 μ‹œν‚¬ 수 μžˆλ‹€.

핡심 κΈ°λŠ₯(Core Concerns)

  • 객체가 μ œκ³΅ν•˜λŠ” 고유의 κΈ°λŠ₯
  • μ„œλΉ„μŠ€ 둜직(λΉ„μ¦ˆλ‹ˆμŠ€ 둜직)

λΆ€κ°€ κΈ°λŠ₯(CROSS-CUTTING CONCERNS)

  • νš‘λ‹¨ κΈ°λŠ₯이라고도 ν•œλ‹€.
  • κ³΅ν†΅μ μœΌλ‘œ μ‚¬μš©λ˜λŠ” 둜직(λΉ„μ¦ˆλ‹ˆμŠ€ λ‘œμ§μ„ μ œμ™Έν•œ 것)
  • ❗핡심 κΈ°λŠ₯을 μ œμ™Έν•œ λͺ¨λ“  것은 μ•„λ‹˜
  • 핡심 κΈ°λŠ₯을 λ³΄μ‘°ν•˜κΈ° μœ„ν•΄ μ œκ³΅λ˜λŠ” κΈ°λŠ₯
  • 둜그 좔적, 둜직, λ³΄μ•ˆ, νŠΈλžœμ μ…˜ κΈ°λŠ₯ 등이 ν¬ν•¨λœλ‹€.
  • 단독 μ‚¬μš© X, 핡심기λŠ₯κ³Ό ν•¨κ»˜ O

☝️ λΆ€κ°€ κΈ°λŠ₯은 보톡 μ—¬λŸ¬ ν΄λž˜μŠ€μ—μ„œ κ³΅ν†΅μ μœΌλ‘œ μ‚¬μš©λ˜λŠ” κ²½μš°κ°€ λ§Žλ‹€.
수백수천개의 ν΄λž˜μŠ€μ—μ„œ κ³΅ν†΅λœ λΆ€κ°€κΈ°λŠ₯을 λΆ€μ—¬ν•œλ‹€κ³  κ°€μ •ν–ˆμ„ λ•Œ 쀑볡 μ½”λ“œ λ°œμƒμ€ 물둠이고 ν•΄λ‹Ή μ½”λ“œμ— μˆ˜μ •μ΄ ν•„μš”ν•œ κ²½μš°κ°€ λ°œμƒν•œλ‹€λ©΄ ...🀯

AOP의 μš©μ–΄

Aspect

  • Advice + Pointcut의 λͺ¨λ“ˆν™”ν•˜μ—¬ μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ— ν¬ν•¨λ˜λŠ” νš‘λ‹¨ κΈ°λŠ₯
  • μ—¬λŸ¬ 객체에 κ³΅ν†΅μ μœΌλ‘œ μ μš©λ˜λŠ” κΈ°λŠ₯

Advisor

  • ν•˜λ‚˜μ˜Advice와 ν•˜λ‚˜μ˜ Pointcut둜 κ΅¬μ„±λœ λͺ¨λ“ˆ

Advice

  • Join pointμ—μ„œ μˆ˜ν–‰λ˜λŠ” μ½”λ“œ (λΆ€κ°€ κΈ°λŠ₯)
  • Aspectλ₯Ό μ–Έμ œ 핡심 μ½”λ“œμ— μ μš©ν•  μ‹œμ μ„ μ •μ˜ν•œλ‹€.

Pointcut

  • 경둜(ex! com.start.aop.order)
  • Join point μ€‘μ—μ„œ Adviceκ°€ 적용될 μœ„μΉ˜λ₯Ό μ„ λ³„ν•˜λŠ” κΈ°λŠ₯
  • AspectJν‘œν˜„μ‹μ„ μ‚¬μš©ν•΄ μ§€μ •ν•œλ‹€.

Join point

  • μ• ν”Œλ¦¬μΌ€μ΄μ…˜ μ‹€ν–‰ νλ¦„μ—μ„œμ˜ νŠΉμ •ν¬μΈνŠΈλ₯Ό λ§ν•œλ‹€.
    • 클래슀 μ΄ˆκΈ°ν™”
    • 객체 μΈμŠ€ν„΄μŠ€ν™”
    • λ©”μ„œλ“œ 호좜
    • ν•„λ“œ μ ‘κ·Ό
    • μ˜ˆμ™Έ λ°œμƒ λ“±
  • AOPλ₯Ό μ μš©ν•  수 μžˆλŠ” λͺ¨λ“  지점을 μ˜λ―Έν•œλ‹€.
  • μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ— μƒˆλ‘œμš΄ λ™μž‘μ„ μΆ”κ°€ν•˜κΈ° μœ„ν•΄ Join point에 관심 μ½”λ“œ(Aspect code)λ₯Ό μΆ”κ°€ν•  수 μžˆλ‹€.
  • AOP에 μ˜ν•΄ Join pointμ „,후에 νš‘λ‹¨ 관심이 μΆ”κ°€λœλ‹€.
  • πŸ’‘Spring AOPμ—μ„œλŠ” λ©”μ„œλ“œ λ ˆλ²¨μ—μ„œλ§Œ 적용 κ°€λŠ₯ν•˜λ‹€.

πŸ’‘ μŠ€ν”„λ§ AOPλŠ” ν”„λ‘μ‹œ 방식을 μ‚¬μš©ν•˜λ―€λ‘œ 항상 λ©”μ„œλ“œ μ‹€ν–‰ 지점을 Join point둜 κ°–λŠ”λ‹€. λ”°λΌμ„œ Pointcut도 λ©”μ„œλ“œ μ‹€ν–‰ μ§€μ μœΌλ‘œ μ œν•œλœλ‹€.

β˜οΈν”„λ‘μ‹œ(Proxy)
컴퓨터 λ„€νŠΈμ›Œν¬μ—μ„œ λ‹€λ₯Έ μ„œλ²„ μƒμ˜ μžμ›μ„ μ°ΎλŠ” ν΄λΌμ΄μ–ΈνŠΈλ‘œλΆ€ν„° μš”μ²­μ„ λ°›μ•„ μ€‘κ³„ν•˜λŠ” μ„œλ²„.
λΆ„μ‚° μ‹œμŠ€ν…œμ˜ ꡬ쑰λ₯Ό λ‹¨μˆœν™”ν•˜κ³  μΊ‘μŠν™”ν•˜μ—¬ μ„œλΉ„μŠ€μ˜ λ³΅μž‘λ„λ₯Ό μ€„μ΄λŠ” 역할을 ν•œλ‹€.
☝️ μŠ€ν”„λ§ AOPλŠ” ν”„λ‘μ‹œ 기반의 AOP κ΅¬ν˜„μ²΄μ΄λ‹€.
μ ‘κ·Ό μ œμ–΄ 및 λΆ€κ°€ κΈ°λŠ₯을 μΆ”κ°€ν•˜κΈ° μœ„ν•΄μ„œ ν”„λ‘μ‹œ 객체λ₯Ό μ‚¬μš©ν•œλ‹€.

Weaving

  • AOPκ°€ κ΅¬ν˜„λ˜λŠ” κ³Όμ •
  • Pointcut으둜 κ²°μ •ν•œ νƒ€κ²Ÿμ˜ Join point에 Adviceλ₯Ό μ μš©ν•˜λŠ” 것
  • 핡심 κΈ°λŠ₯ μ½”λ“œμ— 영ν–₯을 주지 μ•Šκ³  λΆ€κ°€ κΈ°λŠ₯을 μΆ”κ°€ν•  수 μžˆλ‹€.
  • AOP μ μš©μ„ μœ„ν•΄ Aspect 객체에 μ—°κ²°ν•œ μƒνƒœμ΄λ‹€.

πŸ’‘μœ„λΉ™(Weaving)은 컴파일 νƒ€μž„(μžλ°”->클래슀둜 컴파일될 λ•Œ), 클래슀 λ‘œλ“œ νƒ€μž„(컴파일 이후 λ©”λͺ¨λ¦¬μ— μ˜¬λΌκ°€λŠ” μ‹œμ ), λŸ°νƒ€μž„(μ‹€ν–‰ 쀑일 λ•Œ) 3가지 적용 μ‹œμ μ΄ μžˆλ‹€.
β˜οΈλ‹¨, 컴파일 νƒ€μž„κ³Ό 클래슀 λ‘œλ“œ νƒ€μž„μ€ AspectJμ—μ„œ μ‚¬μš©ν•˜λŠ” λ°©μ‹μœΌλ‘œ Spring AOPμ—μ„œλŠ” μ‚¬μš©μ΄ λΆˆκ°€ν•˜λ‹€.

πŸ’‘ λŸ°νƒ€μž„ == ν”„λ‘μ‹œ 방식이라고 ν•˜λ©°, μŠ€ν”„λ§ μ»¨ν…Œμ΄λ„ˆκ°€ 객체λ₯Ό 생성할 λ•Œ ν”„λ‘μ‹œ 객체λ₯Ό μžλ™μœΌλ‘œ μƒμ„±ν•˜κ³  원본 객체 λŒ€μ‹  ν”„λ‘μ‹œλ₯Ό λΉˆμ— λ“±λ‘ν•œλ‹€.

Target

  • 핡심 κΈ°λŠ₯을 λ‹΄κ³  μžˆλŠ” λͺ¨λ“ˆλ‘œ λΆ€κ°€ κΈ°λŠ₯을 λΆ€μ—¬ν•  λŒ€μƒ
  • Adviceλ₯Ό λ°›λŠ” 객체이고 Pointcut으둜 κ²°μ •λœλ‹€.

νƒ€μž…λ³„ Advice

Advice

: 핡심 κΈ°λŠ₯에 적용될 λΆ€κ°€ κΈ°λŠ₯의 μ½”λ“œ

Advice의 μˆœμ„œ

  • 기본적으둜 μˆœμ„œλ₯Ό 보μž₯해주지 μ•Šμ§€λ§Œ @Order μ• λ„ˆν…Œμ΄μ…˜μ„ μ μš©ν•˜λ©΄ μˆœμ„œλ₯Ό μ •ν•  수 μžˆλ‹€.
    • 단, 클래슀 λ‹¨μœ„λ‘œ μ μš©ν•  수 μžˆλ‹€.
    • ν•˜λ‚˜μ˜ Aspect에 μ—¬λŸ¬ Adviceκ°€ μ‘΄μž¬ν•œλ‹€λ©΄ μˆœμ„œλ₯Ό 보μž₯ν•  수 μ—†λ‹€.
  • μˆœμ„œλ₯Ό μ§€μΌœμ•Ό ν•œλ‹€λ©΄ Aspectλ₯Ό λ³„λ„μ˜ 클래슀둜 뢄리해야 ν•œλ‹€.

Advice의 μ’…λ₯˜

Before

  • Join pointμ‹€ν–‰ 이전에 μ‹€ν–‰
  • νƒ€κ²Ÿ λ©”μ„œλ“œκ°€ μ‹€ν–‰λ˜κΈ° 전에 μ²˜λ¦¬ν•΄μ•Όν•  ν•„μš”κ°€ μžˆλŠ” λΆ€κ°€ κΈ°λŠ₯을 호좜 전에 곡톡 κΈ°λŠ₯을 μ‹€ν–‰
  • Before Advice둜 κ΅¬ν˜„ν•œ λ©”μ„œλ“œλŠ” 일반적으둜 Void의 λ¦¬ν„΄νƒ€μž…μ„ κ°–λŠ”λ‹€.
  • β—μ£Όμ˜ : λ©”μ„œλ“œμ—μ„œ μ˜ˆμ™Έλ₯Ό λ°œμƒμ‹œν‚¬ 경우 λŒ€μƒ 객체의 λ©”μ„œλ“œκ°€ ν˜ΈμΆœλ˜μ§€ μ•Šκ²Œλœλ‹€.

After returning

  • λ©”μ„œλ“œκ°€ μ˜ˆμ™Έ 없이 정상 μ™„λ£Œ ν›„ Join point μ‹€ν–‰
@AfterReturning(value = "hello.aop.order.aop.Pointcuts.orderAndService()", returning = "result")
public void doReturn(JoinPoint joinPoint, Object result) {
    log.info("[return] {} return={}", joinPoint.getSignature(), result);
}
  • returning 속성에 μ‚¬μš©λœ 이름은 Advice λ©”μ„œλ“œμ˜ λ§€κ°œλ³€μˆ˜ 이름과 μΌμΉ˜ν•΄μ•Ό ν•œλ‹€.
  • returning μ ˆμ— μ§€μ •λœ νƒ€μž…μ˜ 값을 λ°˜ν™˜ν•˜λŠ” λ©”μ„œλ“œλ§Œ λŒ€μƒμ„ μ‹€ν–‰ν•œλ‹€.

After throwing

  • λ©”μ„œλ“œλ₯Ό μ‹€ν–‰ν•˜λŠ” 도쀑 μ˜ˆμ™Έκ°€ λ°œμƒν•˜λ©΄ 곡톡 κΈ°λŠ₯을 μ‹€ν–‰ν•œλ‹€.
@AfterThrowing(value = "hello.aop.order.aop.Pointcuts.orderAndService()", throwing = "ex")
public void doThrowing(JoinPoint joinPoint, Exception ex) {
    log.info("[ex] {} message={}", joinPoint.getSignature(), ex.getMessage());
}
  • throwing 속성에 μ‚¬μš©λœ 이름은 μ–΄λ“œλ°”μ΄μŠ€ λ©”μ„œλ“œμ˜ λ§€κ°œλ³€μˆ˜ 이름과 μΌμΉ˜ν•΄μ•Ό ν•œλ‹€.
  • throwing μ ˆμ— μ§€μ •λœ νƒ€μž…κ³Ό λ§žμ€ μ˜ˆμ™Έλ₯Ό λŒ€μƒμœΌλ‘œ μ‹€ν–‰ν•œλ‹€.

After(finally)

  • Join point의 λ™μž‘κ³ΌλŠ” 상관없이 μ‹€ν–‰ν•œλ‹€.
  • λ©”μ„œλ“œ μ‹€ν–‰ ν›„ 곡톡 κΈ°λŠ₯을 μ‹€ν–‰ν•œλ‹€.
  • 일반적으둜 λ¦¬μ†ŒμŠ€λ₯Ό ν•΄μ œν•˜λŠ”λ° μ‚¬μš©ν•œλ‹€.

Around(πŸŒŸμ€‘μš”)

  • λ©”μ„œλ“œ 호좜 μ „,후에 μˆ˜ν–‰ν•˜λ©° κ°€μž₯ κ°•λ ₯ν•œ Advice이닀.
    • 쑰인 포인트 μ‹€ν–‰ μ—¬λΆ€ 선택, λ°˜ν™˜ κ°’ λ³€ν™˜, μ˜ˆμ™Έ λ³€ν™˜ 등이 κ°€λŠ₯ν•˜λ‹€
  • λ©”μ„œλ“œ μ‹€ν–‰ μ „, ν›„, μ˜ˆμ™Έ λ°œμƒ μ‹œμ μ— 곡톡 κΈ°λŠ₯을 μ‹€ν–‰ν•©λ‹ˆλ‹€.
  • κ·Έ μ™Έμ˜ κΈ°λŠ₯
    • 쑰인 포인트 μ‹€ν–‰ μ—¬λΆ€ 선택 - joinPoint.proceed()
    • 전달 κ°’ λ³€ν™˜ = joinPoint.proceed(args[])
    • λ°˜ν™˜ κ°’ λ³€ν™˜
    • μ˜ˆμ™Έ λ³€ν™˜
    • try~catch~finallyκ°€ λ“€μ–΄κ°€λŠ” ꡬ문처리 κ°€λŠ₯
  • 첫번째 νŒŒλΌλ―Έν„°λŠ” ProceedingJoinPointλ₯Ό μ‚¬μš©ν•΄μ•Ό ν•œλ‹€.
  • proceed()λ₯Ό 톡해 λŒ€μƒμ„ μ‹€ν–‰ν•œλ‹€.(μ—¬λŸ¬λ²ˆ κ°€λŠ₯)

☝️ Aroundκ°€ κ°€μž₯ λ§Žμ€ κΈ°λŠ₯을 가진 Advice인 것은 λ§žμ§€λ§Œ 상황에 따라 μ •μƒμ μœΌλ‘œ μž‘λ™λ˜μ§€ μ•ŠλŠ” κ²½μš°κ°€ μžˆμœΌλ‹ˆ 상황에 맞게 νŒλ‹¨ν•˜μ—¬ μ‚¬μš©ν•΄μ•Ό ν•œλ‹€.

profile
πŸ§‘β€πŸ’»λ°±μ—”λ“œ 개발자, μ‘°κΈˆμ”© κΎΈμ€€ν•˜κ²Œ

0개의 λŒ“κΈ€