๐ŸŽฏ F-lab Java 8-9์ฃผ์ฐจ ํ†ตํ•ฉ ํ•™์Šต ์ปค๋ฆฌํ˜๋Ÿผ

8-9์ฃผ์ฐจ ์ž๋ฃŒ์˜ ๋ชจ๋“  ํ† ํ”ฝ์„ ๋‘ ์ฃผ์— ๊ฑธ์ณ ์ •๋ฆฌํ•œ ํ•™์Šต ๊ฒฝ๋กœ.
1) 8์ฃผ์ฐจ โ€” ํ”„๋ก์‹œ์˜ ์ง„ํ™” (AOP๊ฐ€ ํ•„์š”ํ•œ ์ด์œ , ๋””์ž์ธ ํŒจํ„ด, ๋™์  ํ”„๋ก์‹œ, ProxyFactory)
2) 9์ฃผ์ฐจ โ€” Spring AOP ์‹ค์ „ (์ž๋™ ํ”„๋ก์‹œ, @Aspect, AOP ์šฉ์–ด, @Transactional ํ•จ์ •, ํŠธ๋žœ์žญ์…˜ ์ „ํŒŒ)

7์ฃผ์ฐจ์—์„œ @Transactional์˜ ํ”„๋ก์‹œ ํŒจํ„ด์„ ๋ง›๋ดค๋‹ค๋ฉด, 8-9์ฃผ์ฐจ๋Š” ๊ทธ ํ”„๋ก์‹œ๊ฐ€ ์–ด๋–ป๊ฒŒ ๋งŒ๋“ค์–ด์ง€๊ณ  ์ ์šฉ๋˜๋Š”์ง€ ์˜ ๋ชจ๋“  ๋ฉ”์ปค๋‹ˆ์ฆ˜์„ ํŒŒํ—ค์นœ๋‹ค.

๊น€์˜ํ•œ์˜ ์Šคํ”„๋ง ํ•ต์‹ฌ ์›๋ฆฌ - ๊ณ ๊ธ‰ํŽธ ์ „์ฒด ํ๋ฆ„์ด ์••์ถ•๋˜์–ด ์žˆ๋‹ค. F-lab ์ž๋ฐ” ์ปค๋ฆฌํ˜๋Ÿผ์˜ ํ•˜์ด๋ผ์ดํŠธ ์ด์ž ๊ฐ€์žฅ ๋ถ„๋Ÿ‰์ด ๋งŽ์€ ์ฃผ์ฐจ๋‹ค.


๐Ÿ“Š ํ•™์Šต ๊ฒฝ๋กœ ํ•œ๋ˆˆ์— ๋ณด๊ธฐ

[Part A โ€” 8์ฃผ์ฐจ: ํ”„๋ก์‹œ์˜ ์ง„ํ™”]
  [Phase 1] AOP ์ž…๋ฌธ๊ณผ ๋™๊ธฐ
     โ†“
  [Phase 2] ๋””์ž์ธ ํŒจํ„ด์˜ ์ง„ํ™” โ€” ํ…œํ”Œ๋ฆฟ ๋ฉ”์„œ๋“œ โ†’ ์ „๋žต ํŒจํ„ด
     โ†“
  [Phase 3] ์ฝœ๋ฐฑ๊ณผ ํ”„๋ก์‹œ์˜ ๋งŒ๋‚จ โ€” ํ…œํ”Œ๋ฆฟ ์ฝœ๋ฐฑ โ†’ ํ”„๋ก์‹œ ๊ฐœ๋…
     โ†“
  [Phase 4] ํ”„๋ก์‹œ ํŒจํ„ด vs ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ํŒจํ„ด
     โ†“
  [Phase 5] ๋™์  ํ”„๋ก์‹œ ๊ธฐ์ˆ  โ€” Reflection / JDK / CGLIB
     โ†“
  [Phase 6] ProxyFactory โ€” ์Šคํ”„๋ง์˜ ํ†ตํ•ฉ ์ถ”์ƒํ™” โ—„ 8์ฃผ์ฐจ ์ •์ 

[Part B โ€” 9์ฃผ์ฐจ: Spring AOP ์‹ค์ „]
  [Phase 7] ๋นˆ ํ›„์ฒ˜๋ฆฌ๊ธฐ์™€ ์ž๋™ ํ”„๋ก์‹œ ์ƒ์„ฑ๊ธฐ
     โ†“
  [Phase 8] @Aspect์™€ AOP ์šฉ์–ด ์™„์ „ ์ •๋ฆฌ
     โ†“
  [Phase 9] Spring AOP ์‹ค์ „ ๊ตฌํ˜„ ํŒจํ„ด
     โ†“
  [Phase 10] @Transactional์˜ ํ•จ์ •๊ณผ ํŠธ๋žœ์žญ์…˜ ์ „ํŒŒ โ—„ 9์ฃผ์ฐจ ์ •์ 

์ด 10 Phase ร— 35 Unit (5ยท6์ฃผ์ฐจ์˜ ํ•ฉ๊ณผ ๋น„์Šทํ•œ ๋ถ„๋Ÿ‰)

๐Ÿ”— 1~9์ฃผ์ฐจ ํ๋ฆ„ ์ •๋ฆฌ

์ฃผ์ฐจ์ฃผ์ œํ•ต์‹ฌ ๋ณ€ํ™”
1์ฃผ์ฐจOOPยทJVMยทGCยท์ปฌ๋ ‰์…˜ยทI/O ๊ฐœ๋ก ์ž๋ฐ” ํฐ ๊ทธ๋ฆผ
2์ฃผ์ฐจJVM ๋‚ด๋ถ€ยท๋ฐ”์ดํŠธ์ฝ”๋“œยทG1 GC"์–ด๋–ป๊ฒŒ ๋Œ์•„๊ฐ€๋‚˜"
3์ฃผ์ฐจ์ปฌ๋ ‰์…˜ยท์ œ๋„ค๋ฆญยทํ•จ์ˆ˜ํ˜•์ž๋ฐ” ํ‘œํ˜„๋ ฅ
4์ฃผ์ฐจ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋”ฉยท๋™์‹œ์„ฑยทExecutor๋™์‹œ์„ฑ ์ •๋ณต
5์ฃผ์ฐจAtomic + Spring IoC/DI ์ž…๋ฌธ์ž๋ฐ” โ†’ Spring ๋‹ค๋ฆฌ
6์ฃผ์ฐจํ…Œ์ŠคํŠธ + ์›น ์ธํ”„๋ผ + DB ์ ‘๊ทผ ์ง„ํ™”Spring ์‹ค์ „ ํ™˜๊ฒฝ
7์ฃผ์ฐจJPA/ORM + ํŠธ๋žœ์žญ์…˜ ์ถ”์ƒํ™”DB ์ถ”์ƒํ™”์˜ ์ •์ 
8์ฃผ์ฐจ (์ง€๊ธˆ)ํ”„๋ก์‹œ์˜ ์ง„ํ™”AOP ๋ฉ”์ปค๋‹ˆ์ฆ˜ ์ดํ•ด
9์ฃผ์ฐจ (์ง€๊ธˆ)Spring AOP ์‹ค์ „ + ํŠธ๋žœ์žญ์…˜ ์ „ํŒŒAOP ์‹ค์ „ ํ™œ์šฉ

๐Ÿ—“๏ธ ๊ถŒ์žฅ ํ•™์Šต ์ผ์ • (์••์ถ• 14์ผ)

DayPhaseํ•™์Šต ๋ชฉํ‘œ
Week 1
1์ผ์ฐจPhase 1AOP ๋™๊ธฐ, ๋กœ๊ทธ ์ถ”์ ๊ธฐ, ThreadLocal
2์ผ์ฐจPhase 2ํ…œํ”Œ๋ฆฟ ๋ฉ”์„œ๋“œ + ์ „๋žต ํŒจํ„ด
3์ผ์ฐจPhase 3ํ…œํ”Œ๋ฆฟ ์ฝœ๋ฐฑ ํŒจํ„ด, ํ”„๋ก์‹œ ๊ฐœ๋…
4์ผ์ฐจPhase 4ํ”„๋ก์‹œ vs ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ
5์ผ์ฐจPhase 5Reflection + JDK ๋™์  ํ”„๋ก์‹œ + CGLIB
6-7์ผ์ฐจPhase 6ProxyFactory + Advice + Pointcut + Advisor (โ˜… 8์ฃผ์ฐจ ์ •์ )
Week 2
8์ผ์ฐจPhase 7๋นˆ ํ›„์ฒ˜๋ฆฌ๊ธฐ + ์ž๋™ ํ”„๋ก์‹œ ์ƒ์„ฑ๊ธฐ
9์ผ์ฐจPhase 8@Aspect + AOP ์šฉ์–ด
10์ผ์ฐจPhase 9Spring AOP ์‹ค์ „ ํŒจํ„ด
11-12์ผ์ฐจPhase 10@Transactional ํ•จ์ • + ํŠธ๋žœ์žญ์…˜ ์ „ํŒŒ (โ˜… 9์ฃผ์ฐจ ์ •์ )
13-14์ผ์ฐจ์ข…ํ•ฉ ์ž๊ธฐ ์ ๊ฒ€ + ์‹ค์Šต์ „์ฒด ์ •๋ฆฌ

์—ฌ์œ  ์ผ์ • (21์ผ): ๊ฐ ์ •์  Phase์— +2์ผ์”ฉ, ๊ทธ๋ฆฌ๊ณ  9-์„น์…˜ ๋งˆ์Šคํ„ฐ ํ”„๋กฌํ”„ํŠธ๋กœ ํ•ต์‹ฌ Unit์„ ๊นŠ์ด ํŒŒ๋Š” ์‹œ๊ฐ„ ํ™•๋ณด.


๐ŸŒŸ Part A โ€” 8์ฃผ์ฐจ: ํ”„๋ก์‹œ์˜ ์ง„ํ™”

๐Ÿ“š Phase 1 โ€” AOP ์ž…๋ฌธ๊ณผ ๋™๊ธฐ

๋ชฉํ‘œ: "์™œ AOP๊ฐ€ ํ•„์š”ํ•œ๊ฐ€"๋ฅผ ์ฝ”๋“œ์˜ ๊ณ ํ†ต์œผ๋กœ ์ง์ ‘ ์ดํ•ดํ•œ๋‹ค. 7์ฃผ์ฐจ์—์„œ ๋ณธ @Transactional์˜ ์ •์ฒด๋ฅผ ๋” ๊นŠ์ด ์•Œ๊ธฐ ์œ„ํ•œ ์ถœ๋ฐœ์ .

Unit 1.1 โ€” AOP๋ž€ ๋ฌด์—‡์ธ๊ฐ€ (๊ด€์  ์ง€ํ–ฅ ํ”„๋กœ๊ทธ๋ž˜๋ฐ)

์„ ์ˆ˜ ์ง€์‹: 7์ฃผ์ฐจ Phase 7 (@Transactional)

ํ•ต์‹ฌ ๊ฐœ๋…

AOP (Aspect Oriented Programming) = ๊ด€์  ์ง€ํ–ฅ ํ”„๋กœ๊ทธ๋ž˜๋ฐ

ํ•ต์‹ฌ ํ†ต์ฐฐ:

  • ์–ด๋–ค ๋กœ์ง์„ ํ•ต์‹ฌ ๊ด€์  + ๋ถ€๊ฐ€ ๊ด€์  ์œผ๋กœ ๋‚˜๋ˆ ์„œ ๋ณธ๋‹ค
  • ๊ฐ ๊ด€์ ์„ ๋ณ„๋„๋กœ ๋ชจ๋“ˆํ™”

ํ•ต์‹ฌ vs ๋ถ€๊ฐ€:

  • ํ•ต์‹ฌ ๊ด€์ : ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง (์ฃผ๋ฌธ ์ฒ˜๋ฆฌ, ํšŒ์› ๊ฐ€์ž… ๋“ฑ)
  • ๋ถ€๊ฐ€ ๊ด€์ : ๋กœ๊น…, ํŠธ๋žœ์žญ์…˜, DB ์—ฐ๊ฒฐ, ๋ณด์•ˆ, ์บ์‹ฑ ๋“ฑ

ํฉ์–ด์ง„ ๊ด€์‹ฌ์‚ฌ (Crosscutting Concerns):

  • ์—ฌ๋Ÿฌ ํด๋ž˜์Šค์— ๋ฐ˜๋ณต์ ์œผ๋กœ ๋“ฑ์žฅํ•˜๋Š” ์ฝ”๋“œ
  • OOP๋งŒ์œผ๋กœ๋Š” ๊น”๋”ํžˆ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์–ด๋ ค์›€
  • โ†’ AOP์˜ ๋“ฑ์žฅ ์ด์œ 

์ž๊ธฐ ์ ๊ฒ€

  • 7์ฃผ์ฐจ์˜ @Transactional์ด ์ด ์ •์˜์˜ ์–ด๋””์— ํ•ด๋‹นํ•˜๋Š”๊ฐ€?
  • "ํฉ์–ด์ง„ ๊ด€์‹ฌ์‚ฌ"์˜ ์‹ค์ œ ์‚ฌ๋ก€ 3๊ฐ€์ง€๋ฅผ ๋“ค์–ด๋ณด๋ผ

Unit 1.2 โ€” ๋กœ๊ทธ ์ถ”์ ๊ธฐ๋กœ ๋ณด๋Š” ํฉ์–ด์ง„ ๊ด€์‹ฌ์‚ฌ

์„ ์ˆ˜ ์ง€์‹: Unit 1.1

ํ•ต์‹ฌ ์‹œ๋‚˜๋ฆฌ์˜ค

๋กœ๊ทธ ์ถ”์ ๊ธฐ๋ž€?:

  • ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ ์‹œ ์ž๋™์œผ๋กœ ๋กœ๊ทธ ๋‚จ๊ธฐ๊ธฐ
  • ํ˜ธ์ถœ ๊นŠ์ด, ์‹คํ–‰ ์‹œ๊ฐ„, ์˜ˆ์™ธ๊นŒ์ง€ ์ถ”์ 

์˜ˆ์‹œ ์ถœ๋ ฅ:

์ •์ƒ ์š”์ฒญ
[796bccd9] OrderController.request()
[796bccd9] |-->OrderService.orderItem()
[796bccd9] | |-->OrderRepository.save()
[796bccd9] | |<--OrderRepository.save() time=1004ms
[796bccd9] |<--OrderService.orderItem() time=1014ms
[796bccd9] OrderController.request() time=1016ms

์˜ˆ์™ธ ๋ฐœ์ƒ
[b7119f27] OrderController.request()
[b7119f27] |-->OrderService.orderItem()
[b7119f27] | |<X-OrderService.orderItem() time=10ms ex=...

๋ฌธ์ œ:

  • ๋ชจ๋“  ๋ฉ”์„œ๋“œ์— try-catch + ๋กœ๊ทธ ์‹œ์ž‘/์ข…๋ฃŒ ์ฝ”๋“œ ์ถ”๊ฐ€ ํ•„์š”
  • "๋ฐฐ๋ณด๋‹ค ๋ฐฐ๊ผฝ์ด ๋” ํฐ" ์ƒํ™ฉ
  • 100๊ฐœ ๋ฉ”์„œ๋“œ๋ฉด 100๊ตฐ๋ฐ ์ˆ˜์ •

์ž๊ธฐ ์ ๊ฒ€

  • ๋กœ๊ทธ ์ถ”์ ๊ธฐ์˜ ์–ด๋–ค ๋ถ€๋ถ„์ด "๋ณ€ํ•˜์ง€ ์•Š๋Š” ๊ฒƒ"์ธ๊ฐ€?
  • ์–ด๋–ค ๋ถ€๋ถ„์ด "๋ณ€ํ•˜๋Š” ๊ฒƒ"์ธ๊ฐ€?

Unit 1.3 โ€” ThreadLocal โ€” ์‹ฑ๊ธ€ํ†ค ํ™˜๊ฒฝ์˜ ๋™์‹œ์„ฑ ํ•ด๊ฒฐ

์„ ์ˆ˜ ์ง€์‹: 4์ฃผ์ฐจ Phase 4 (synchronized), 5์ฃผ์ฐจ Phase 8 (์‹ฑ๊ธ€ํ†ค ๋นˆ)

ํ•ต์‹ฌ ๊ฐœ๋…

๋ฌธ์ œ ์ƒํ™ฉ:

  • ๋กœ๊ทธ ์ถ”์ ๊ธฐ = ์‹ฑ๊ธ€ํ†ค ๋นˆ
  • ์—ฌ๋Ÿฌ ์š”์ฒญ์ด ๋™์‹œ์— ํ˜ธ์ถœ โ†’ ๊ฐ™์€ ์ธ์Šคํ„ด์Šค์˜ ์ƒํƒœ๋ฅผ ๋™์‹œ ๋ณ€๊ฒฝ
  • โ†’ ํŠธ๋žœ์žญ์…˜ ID, ํ˜ธ์ถœ ๊นŠ์ด ๋“ฑ์ด ์„œ๋กœ ์„ž์ž„

ThreadLocal์˜ ํ•ด๊ฒฐ:

  • ๊ฐ ์Šค๋ ˆ๋“œ๋งˆ๋‹ค ๋…๋ฆฝ์ ์ธ ์ €์žฅ์†Œ ์ œ๊ณต
  • ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ์™€ ๋ฐ์ดํ„ฐ ๊ณต์œ  ์•ˆ ํ•จ
  • synchronized ์—†์ด ์•ˆ์ „
ThreadLocal<String> threadLocal = new ThreadLocal<>();

threadLocal.set("Thread-1 ๋ฐ์ดํ„ฐ");  // ์ด ์Šค๋ ˆ๋“œ๋งŒ ๋ณด์ž„
String value = threadLocal.get();    // ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ๋Š” ๋‹ค๋ฅธ ๊ฐ’

โš ๏ธ ์น˜๋ช…์  ํ•จ์ • โ€” remove() ํ•„์ˆ˜:

  • ์Šค๋ ˆ๋“œ ํ’€ ํ™˜๊ฒฝ์—์„œ ์Šค๋ ˆ๋“œ๊ฐ€ ์žฌ์‚ฌ์šฉ ๋จ
  • ThreadLocal ๊ฐ’์ด ๋‚จ์•„์žˆ์œผ๋ฉด โ†’ ๋‹ค์Œ ์š”์ฒญ์— ์ด์ „ ์‚ฌ์šฉ์ž์˜ ๋ฐ์ดํ„ฐ ๋…ธ์ถœ
  • ๋ฐ˜๋“œ์‹œ finally์—์„œ remove()
try {
    threadLocal.set(data);
    // ์ž‘์—…
} finally {
    threadLocal.remove();  // โœ… ํ•„์ˆ˜!
}

์ž๊ธฐ ์ ๊ฒ€

  • ThreadLocal์ด ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋“œ๋ฅผ "์ˆœ์ฐจ์ "์œผ๋กœ ๋งŒ๋“œ๋Š”๊ฐ€? (ํžŒํŠธ: NO)
  • remove()๋ฅผ ๊นœ๋ฐ•ํ•˜๋ฉด ์–ด๋–ค ๋ณด์•ˆ ์‚ฌ๊ณ ๊ฐ€? (ํžŒํŠธ: ์‚ฌ์šฉ์ž ์ •๋ณด ์œ ์ถœ)

๐Ÿ“š Phase 2 โ€” ๋””์ž์ธ ํŒจํ„ด์˜ ์ง„ํ™”

๋ชฉํ‘œ: "๋ณ€ํ•˜๋Š” ๊ฒƒ๊ณผ ๋ณ€ํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์„ ๋ถ„๋ฆฌ"๋ผ๋Š” ์ข‹์€ ์„ค๊ณ„์˜ ์›์น™์„ ๋‘ ๊ฐ€์ง€ ํŒจํ„ด(ํ…œํ”Œ๋ฆฟ ๋ฉ”์„œ๋“œ โ†’ ์ „๋žต)์„ ํ†ตํ•ด ์ฝ”๋“œ๋กœ ์ตํžŒ๋‹ค.

Unit 2.1 โ€” ๋ณ€ํ•˜๋Š” ๊ฒƒ๊ณผ ๋ณ€ํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์˜ ๋ถ„๋ฆฌ

์„ ์ˆ˜ ์ง€์‹: Phase 1, 5์ฃผ์ฐจ Phase 5

ํ•ต์‹ฌ ์›์น™

"์ข‹์€ ์„ค๊ณ„๋Š” ๋ณ€ํ•˜๋Š” ๊ฒƒ๊ณผ ๋ณ€ํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์„ ๋ถ„๋ฆฌํ•˜๋Š” ๊ฒƒ์ด๋‹ค"

์˜ˆ์‹œ โ€” ์‹œ๊ฐ„ ์ธก์ • ๋กœ์ง:

private void logic1() {
    long startTime = System.currentTimeMillis();  // โ† ๋ณ€ํ•˜์ง€ ์•Š์Œ
    log.info("๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง1 ์‹คํ–‰");                 // โ† ๋ณ€ํ•จ
    long endTime = System.currentTimeMillis();    // โ† ๋ณ€ํ•˜์ง€ ์•Š์Œ
    log.info("resultTime={}", endTime - startTime); // โ† ๋ณ€ํ•˜์ง€ ์•Š์Œ
}

private void logic2() {
    long startTime = System.currentTimeMillis();  // โ† ๋ณ€ํ•˜์ง€ ์•Š์Œ
    log.info("๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง2 ์‹คํ–‰");                 // โ† ๋ณ€ํ•จ
    long endTime = System.currentTimeMillis();    // โ† ๋ณ€ํ•˜์ง€ ์•Š์Œ
    log.info("resultTime={}", endTime - startTime); // โ† ๋ณ€ํ•˜์ง€ ์•Š์Œ
}

โ†’ ์‹œ๊ฐ„ ์ธก์ •์€ ๊ฐ™์€๋ฐ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง๋งŒ ๋‹ค๋ฆ„

์ž๊ธฐ ์ ๊ฒ€

  • 5์ฃผ์ฐจ ํ† ๋น„์˜ ์Šคํ”„๋ง์—์„œ ๋ณธ "๊ด€์‹ฌ์‚ฌ ๋ถ„๋ฆฌ"์™€ ๊ฐ™์€ ์›์น™์ธ๊ฐ€?
  • "๋ณ€ํ•˜๋Š” ๋ถ€๋ถ„"์„ ๋ถ„๋ฆฌํ•˜๋Š” ๊ฐ€์žฅ ๋‹จ์ˆœํ•œ ๋ฐฉ๋ฒ•์€? (ํžŒํŠธ: ๋ฉ”์„œ๋“œ ์ถ”์ถœ, ๊ทธ๋Ÿฌ๋‚˜ ํ•œ๊ณ„ ์žˆ์Œ)

Unit 2.2 โ€” ํ…œํ”Œ๋ฆฟ ๋ฉ”์„œ๋“œ ํŒจํ„ด

์„ ์ˆ˜ ์ง€์‹: Unit 2.1, 5์ฃผ์ฐจ Unit 5.1

ํ•ต์‹ฌ ๊ฐœ๋…

"์Šˆํผํด๋ž˜์Šค์— ๋ณ€ํ•˜์ง€ ์•Š๋Š” ํ…œํ”Œ๋ฆฟ์„ ๋‘๊ณ , ๋ณ€ํ•˜๋Š” ๋ถ€๋ถ„์„ ์ž์‹ ํด๋ž˜์Šค์— ๋‘๋Š” ํŒจํ„ด"

public abstract class AbstractTemplate {
    public void execute() {
        long startTime = System.currentTimeMillis();
        call();  // โ† ๋ณ€ํ•˜๋Š” ๋ถ€๋ถ„ (์ž์‹์ด ๊ตฌํ˜„)
        long endTime = System.currentTimeMillis();
        log.info("resultTime={}", endTime - startTime);
    }
    
    protected abstract void call();
}

public class SubClassLogic1 extends AbstractTemplate {
    @Override
    protected void call() {
        log.info("๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง1 ์‹คํ–‰");
    }
}

์ต๋ช… ๋‚ด๋ถ€ ํด๋ž˜์Šค ํ™œ์šฉ:

AbstractTemplate template = new AbstractTemplate() {
    @Override
    protected void call() {
        log.info("๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง1 ์‹คํ–‰");
    }
};
template.execute();

์ž๊ธฐ ์ ๊ฒ€

  • 5์ฃผ์ฐจ์—์„œ ํ† ๋น„์˜ ์Šคํ”„๋ง์ด ๊ฐ™์€ ํŒจํ„ด์„ ์–ด๋–ป๊ฒŒ ์‚ฌ์šฉํ–ˆ๋Š”๊ฐ€? (ํžŒํŠธ: UserDao + getConnection)
  • ์ž์‹ ํด๋ž˜์Šค๊ฐ€ ๋ถ€๋ชจ์˜ ์–ด๋–ค ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•˜๋Š”๊ฐ€?

Unit 2.3 โ€” ํ…œํ”Œ๋ฆฟ ๋ฉ”์„œ๋“œ ํŒจํ„ด์˜ ํ•œ๊ณ„ (์ƒ์†์˜ ๊ฒฐํ•ฉ)

์„ ์ˆ˜ ์ง€์‹: Unit 2.2

ํ•ต์‹ฌ ํ•œ๊ณ„

์ƒ์†์˜ ๊ฐ•ํ•œ ๊ฒฐํ•ฉ:

  • ์ž์‹ ํด๋ž˜์Šค ์ž…์žฅ์—์„œ ๋ถ€๋ชจ์˜ ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•˜์ง€๋„ ์•Š๋Š”๋ฐ ์ƒ์†ํ•ด์•ผ ํ•จ
  • ์ž์‹ ์ฝ”๋“œ extends AbstractTemplate โ†’ ๋ถ€๋ชจ์— ๊ฐ•ํ•˜๊ฒŒ ์˜์กด
  • ๋ถ€๋ชจ ๋ณ€๊ฒฝ ์‹œ ์ž์‹๋“ค์—๊ฒŒ ์˜ํ–ฅ ์ „ํŒŒ

๋ณต์žกํ•จ:

  • ์ž‘์—…๋งˆ๋‹ค ๋ณ„๋„ ํด๋ž˜์Šค ๋˜๋Š” ์ต๋ช… ๋‚ด๋ถ€ ํด๋ž˜์Šค ํ•„์š”
  • ์ฝ”๋“œ๋Ÿ‰ ์ฆ๊ฐ€

ํ•ด๊ฒฐ์˜ ๋ฐฉํ–ฅ:

  • ์ƒ์†(extends) ๋Œ€์‹  ํ•ฉ์„ฑ(composition)
  • = ์ „๋žต ํŒจํ„ด

์ž๊ธฐ ์ ๊ฒ€

  • "Composition over Inheritance" ์›์น™์˜ ์˜๋ฏธ๋Š”?
  • 5์ฃผ์ฐจ Phase 5.3์˜ "๋‘ ํŒจํ„ด์˜ ํ•œ๊ณ„"์™€ ๊ฐ™์€ ๋งฅ๋ฝ์ธ๊ฐ€?

Unit 2.4 โ€” ์ „๋žต ํŒจํ„ด (์œ„์ž„์œผ๋กœ ํ•ด๊ฒฐ)

์„ ์ˆ˜ ์ง€์‹: Unit 2.3, 5์ฃผ์ฐจ Unit 6.3

ํ•ต์‹ฌ ๊ฐœ๋…

"๋ณ€ํ•˜์ง€ ์•Š๋Š” ๋ถ€๋ถ„์„ Context์—, ๋ณ€ํ•˜๋Š” ๋ถ€๋ถ„์„ Strategy ์ธํ„ฐํŽ˜์ด์Šค๋กœ"

์ƒ์† ๋Œ€์‹  ์œ„์ž„:

public interface Strategy {
    void call();
}

public class StrategyLogic1 implements Strategy {
    @Override
    public void call() {
        log.info("๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง1 ์‹คํ–‰");
    }
}

public class ContextV1 {
    private Strategy strategy;
    
    public ContextV1(Strategy strategy) {
        this.strategy = strategy;  // ์œ„์ž„
    }
    
    public void execute() {
        long startTime = System.currentTimeMillis();
        strategy.call();  // โ† ์œ„์ž„
        long endTime = System.currentTimeMillis();
        log.info("resultTime={}", endTime - startTime);
    }
}

๋žŒ๋‹ค๋กœ ๋” ๊ฐ„๊ฒฐํ•˜๊ฒŒ:

ContextV1 context = new ContextV1(() -> log.info("๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง1"));
context.execute();

ํ•ต์‹ฌ ํ†ต์ฐฐ:

"Context๋Š” Strategy ์ธํ„ฐํŽ˜์ด์Šค์—๋งŒ ์˜์กด" โ†’ Spring์˜ DI์™€ ๊ฐ™์€ ์‚ฌ์ƒ

์ž๊ธฐ ์ ๊ฒ€

  • 5์ฃผ์ฐจ์˜ ConnectionMaker โ†’ UserDao ํŒจํ„ด๊ณผ ๋™์ผํ•œ๊ฐ€?
  • ๋žŒ๋‹ค๊ฐ€ ๊ฐ€๋Šฅํ•œ ์ด์œ ๋Š”? (ํžŒํŠธ: ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค)

๐Ÿ“š Phase 3 โ€” ์ฝœ๋ฐฑ๊ณผ ํ”„๋ก์‹œ์˜ ๋งŒ๋‚จ

๋ชฉํ‘œ: ์ „๋žต ํŒจํ„ด์˜ ํ•œ๊ณ„๋ฅผ ์ฝœ๋ฐฑ ํŒจํ„ด์œผ๋กœ ๊ทน๋ณตํ•˜๊ณ , ๊ทธ๋ž˜๋„ ๋‚จ๋Š” ํ•œ๊ณ„๋ฅผ ํ”„๋ก์‹œ๋กœ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•œ ์ถœ๋ฐœ์ ์— ์„ ๋‹ค.

Unit 3.1 โ€” ์‹คํ–‰ ์‹œ์  ํŒŒ๋ผ๋ฏธํ„ฐ ์ „๋‹ฌ (์ „๋žต ํŒจํ„ด V2)

์„ ์ˆ˜ ์ง€์‹: Unit 2.4

ํ•ต์‹ฌ ๊ฐœ๋…

Context V1์˜ ํ•œ๊ณ„:

  • Context์™€ Strategy๋ฅผ ๋ฏธ๋ฆฌ ์กฐ๋ฆฝ ํ›„ ์‚ฌ์šฉ
  • ์ „๋žต ๋ณ€๊ฒฝํ•˜๋ ค๋ฉด ์ƒˆ Context ์ธ์Šคํ„ด์Šค ํ•„์š”
  • ์‹ฑ๊ธ€ํ†ค ํ™˜๊ฒฝ์—์„œ๋Š” ๋” ๊นŒ๋‹ค๋กœ์›€

Context V2 โ€” ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋ฐ›๊ธฐ:

public class ContextV2 {
    public void execute(Strategy strategy) {  // โ† ๋งค๋ฒˆ ๋‹ค๋ฅธ ์ „๋žต
        long startTime = System.currentTimeMillis();
        strategy.call();
        long endTime = System.currentTimeMillis();
        log.info("resultTime={}", endTime - startTime);
    }
}

// ์‚ฌ์šฉ
ContextV2 context = new ContextV2();
context.execute(() -> log.info("๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง1"));
context.execute(() -> log.info("๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง2"));

์„  ์กฐ๋ฆฝ ํ›„ ์‹คํ–‰ vs ์‹คํ–‰ ์‹œ์  ์ „๋‹ฌ:

  • ์„  ์กฐ๋ฆฝ: ์˜์กด๊ด€๊ณ„ ์„ค์ • (Spring์˜ DI ๋ฐฉ์‹)
  • ์‹คํ–‰ ์‹œ์ : ๋‹จ์ˆœํžˆ ์ฝ”๋“œ ์กฐ๊ฐ ์‹คํ–‰ ์‹œ ๋” ์ ํ•ฉ

์ž๊ธฐ ์ ๊ฒ€

  • V1๊ณผ V2 ์ค‘ ๋žŒ๋‹ค๋ฅผ ์“ฐ๊ธฐ ๋” ์ž์—ฐ์Šค๋Ÿฌ์šด ์ชฝ์€?
  • ์ž๋ฐ” 8 ์ด์ „์—๋Š” V2๊ฐ€ ๋น„ํ˜„์‹ค์ ์ด์—ˆ๋˜ ์ด์œ ๋Š”? (ํžŒํŠธ: ์ต๋ช… ๋‚ด๋ถ€ ํด๋ž˜์Šค์˜ verbosity)

Unit 3.2 โ€” ํ…œํ”Œ๋ฆฟ ์ฝœ๋ฐฑ ํŒจํ„ด (Spring์˜ XxxTemplate)

์„ ์ˆ˜ ์ง€์‹: Unit 3.1

ํ•ต์‹ฌ ๊ฐœ๋…

์šฉ์–ด ๋งคํ•‘:

  • Context โ†’ Template
  • Strategy โ†’ Callback

ํ…œํ”Œ๋ฆฟ ์ฝœ๋ฐฑ ํŒจํ„ด์€ GOF๊ฐ€ ์•„๋‹Œ ์Šคํ”„๋ง ์ „์šฉ ์šฉ์–ด:

  • ์ „๋žต ํŒจํ„ด V2์—์„œ ํ…œํ”Œ๋ฆฟ๊ณผ ์ฝœ๋ฐฑ์„ ๊ฐ•์กฐํ•œ ํ˜•ํƒœ

Spring์˜ XxxTemplate ์‹œ๋ฆฌ์ฆˆ โญ :

  • JdbcTemplate (6์ฃผ์ฐจ)
  • RestTemplate
  • TransactionTemplate
  • RedisTemplate

โ†’ ์ด๋ฆ„์— "Template"์ด ๋ถ™์œผ๋ฉด ์ด ํŒจํ„ด

์ฝœ๋ฐฑ(Callback)์˜ ์ •์˜:

"๋‹ค๋ฅธ ์ฝ”๋“œ์˜ ์ธ์ˆ˜๋กœ์„œ ๋„˜๊ฒจ์ฃผ๋Š” ์‹คํ–‰ ๊ฐ€๋Šฅํ•œ ์ฝ”๋“œ"

"์ฝ”๋“œ๊ฐ€ ํ˜ธ์ถœ(call)๋˜๋Š”๋ฐ, ์ฝ”๋“œ๋ฅผ ๋„˜๊ฒจ์ค€ ๊ณณ์˜ ๋’ค(back)์—์„œ ์‹คํ–‰๋จ"

template.execute(() -> log.info("๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง1"));
//                โ†‘ ์ด ๋žŒ๋‹ค๊ฐ€ ์ฝœ๋ฐฑ
//                template ์•ˆ์—์„œ "๋‚˜์ค‘์—" ์‹คํ–‰๋จ

์ž๊ธฐ ์ ๊ฒ€

  • 6์ฃผ์ฐจ์˜ JdbcTemplate.query() ์˜ RowMapper ์ธ์ž๊ฐ€ ์ฝœ๋ฐฑ์ธ๊ฐ€?
  • ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์˜ ์ฝœ๋ฐฑ๊ณผ ๊ฐ™์€ ๊ฐœ๋…์ธ๊ฐ€?

Unit 3.3 โ€” ํ”„๋ก์‹œ ๊ฐœ๋…๊ณผ ์กฐ๊ฑด

์„ ์ˆ˜ ์ง€์‹: Phase 3

ํ•ต์‹ฌ ํ•œ๊ณ„ ์ง์‹œ

์ง€๊ธˆ๊นŒ์ง€์˜ ๋ชจ๋“  ๋ฐฉ๋ฒ•(ํ…œํ”Œ๋ฆฟ ๋ฉ”์„œ๋“œ, ์ „๋žต ํŒจํ„ด, ํ…œํ”Œ๋ฆฟ ์ฝœ๋ฐฑ)์˜ ๊ณตํ†ต ํ•œ๊ณ„:

"๊ฒฐ๊ตญ ์›๋ณธ ์ฝ”๋“œ๋ฅผ ์ˆ˜์ •ํ•ด์•ผ ํ•œ๋‹ค"

100๊ฐœ ๋ฉ”์„œ๋“œ๋ฉด 100๊ตฐ๋ฐ ์ˆ˜์ •. ์ด๊ฑธ ์•ˆ ํ•˜๋ ค๋ฉด?

ํ”„๋ก์‹œ(Proxy)์˜ ๋“ฑ์žฅ:

  • "๋Œ€๋ฆฌ์ธ"์ด๋ผ๋Š” ๋œป
  • ํด๋ผ์ด์–ธํŠธ์™€ ์‹ค์ œ ๊ฐ์ฒด ์‚ฌ์ด์— ์ค‘๊ฐ„ ๊ฐ์ฒด ๋ฐฐ์น˜
  • ํด๋ผ์ด์–ธํŠธ๋Š” ํ”„๋ก์‹œ๋ฅผ ํ˜ธ์ถœ
  • ํ”„๋ก์‹œ๊ฐ€ ๋ถ€๊ฐ€ ๊ธฐ๋Šฅ์„ ์ˆ˜ํ–‰ํ•˜๊ณ  ์‹ค์ œ ๊ฐ์ฒด์— ์œ„์ž„

ํ”„๋ก์‹œ๊ฐ€ ๋˜๊ธฐ ์œ„ํ•œ ์กฐ๊ฑด:

  • ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์„œ๋ฒ„ ํ˜ธ์ถœ์ธ์ง€ ํ”„๋ก์‹œ ํ˜ธ์ถœ์ธ์ง€ ๋ชฐ๋ผ์•ผ ํ•จ
  • โ†’ ์„œ๋ฒ„์™€ ํ”„๋ก์‹œ๋Š” ๊ฐ™์€ ์ธํ„ฐํŽ˜์ด์Šค ๊ตฌํ˜„
  • ํด๋ผ์ด์–ธํŠธ ์ฝ”๋“œ ๋ณ€๊ฒฝ ์—†์ด ํ”„๋ก์‹œ ์ฃผ์ž… ๊ฐ€๋Šฅ
[Client] โ†’ [Server]    โ”€โ”€๋ณ€๊ฒฝโ”€โ”€>    [Client] โ†’ [Proxy] โ†’ [Server]
       (DI ํ™œ์šฉ)                              (์ฝ”๋“œ ๋ณ€๊ฒฝ X)

ํ”„๋ก์‹œ์˜ ์ฃผ์š” ๊ธฐ๋Šฅ:

  • ์ ‘๊ทผ ์ œ์–ด: ๊ถŒํ•œ ์ฐจ๋‹จ, ์บ์‹ฑ, ์ง€์—ฐ ๋กœ๋”ฉ
  • ๋ถ€๊ฐ€ ๊ธฐ๋Šฅ ์ถ”๊ฐ€: ์š”์ฒญ/์‘๋‹ต ๋ณ€ํ˜•, ๋กœ๊ทธ, ์‹œ๊ฐ„ ์ธก์ •

์ž๊ธฐ ์ ๊ฒ€

  • DI๊ฐ€ ํ”„๋ก์‹œ ์ ์šฉ์— ์–ด๋–ป๊ฒŒ ๋„์›€์„ ์ฃผ๋Š”๊ฐ€?
  • ํด๋ผ์ด์–ธํŠธ ์ฝ”๋“œ๋Š” ํ”„๋ก์‹œ ์ฃผ์ž…์„ ์•Œ ์ˆ˜ ์žˆ๋Š”๊ฐ€?

๐Ÿ“š Phase 4 โ€” ํ”„๋ก์‹œ ํŒจํ„ด vs ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ํŒจํ„ด

๋ชฉํ‘œ: ๊ฐ™์€ ๋ชจ์–‘์˜ ๋‘ ํŒจํ„ด์„ ์˜๋„ ๋กœ ๊ตฌ๋ถ„ํ•˜๋Š” ๋ฒ•์„ ์ตํžŒ๋‹ค.

Unit 4.1 โ€” ํ”„๋ก์‹œ ํŒจํ„ด (์ ‘๊ทผ ์ œ์–ด โ€” ์บ์‹œ ์˜ˆ์ œ)

์„ ์ˆ˜ ์ง€์‹: Unit 3.3

ํ•ต์‹ฌ ๊ฐœ๋…

ํ”„๋ก์‹œ ํŒจํ„ด = ์ ‘๊ทผ ์ œ์–ด ๋ชฉ์ 

์บ์‹œ ์˜ˆ์ œ:

public class CacheProxy implements Subject {
    private Subject target;
    private String cacheValue;
    
    public CacheProxy(Subject target) {
        this.target = target;
    }
    
    @Override
    public String operation() {
        if (cacheValue == null) {
            cacheValue = target.operation();  // ์ฒ˜์Œ๋งŒ ์‹ค์ œ ํ˜ธ์ถœ
        }
        return cacheValue;  // ๋‘ ๋ฒˆ์งธ๋ถ€ํ„ฐ ์บ์‹œ ๋ฐ˜ํ™˜
    }
}

ํšจ๊ณผ:

  • ์ฒซ ํ˜ธ์ถœ: 1์ดˆ (์‹ค์ œ ๊ฐ์ฒด ํ˜ธ์ถœ)
  • ๋‘ ๋ฒˆ์งธ ํ˜ธ์ถœ: 0์ดˆ (์บ์‹œ)
  • ํด๋ผ์ด์–ธํŠธ ์ฝ”๋“œ ์ˆ˜์ • 0์ค„

์ž๊ธฐ ์ ๊ฒ€

  • "์บ์‹œ๋Š” ์ ‘๊ทผ ์ œ์–ด์ธ๊ฐ€?"์˜ ๋‹ต์€?
  • JPA์˜ 1์ฐจ ์บ์‹œ๋„ ๊ฐ™์€ ํŒจํ„ด์ธ๊ฐ€?

Unit 4.2 โ€” ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ํŒจํ„ด (๋ถ€๊ฐ€ ๊ธฐ๋Šฅ)

์„ ์ˆ˜ ์ง€์‹: Unit 4.1

ํ•ต์‹ฌ ๊ฐœ๋…

๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ํŒจํ„ด = ๋ถ€๊ฐ€ ๊ธฐ๋Šฅ ์ถ”๊ฐ€ ๋ชฉ์ 

์˜ˆ์‹œ โ€” ๋ฉ”์‹œ์ง€ ๊พธ๋ฏธ๊ธฐ + ์‹œ๊ฐ„ ์ธก์ •:

public class MessageDecorator implements Component {
    private Component component;
    
    @Override
    public String operation() {
        String result = component.operation();
        return "*****" + result + "*****";  // ๊พธ๋ฉฐ์คŒ
    }
}

public class TimeDecorator implements Component {
    private Component component;
    
    @Override
    public String operation() {
        long start = System.currentTimeMillis();
        String result = component.operation();
        log.info("time={}ms", System.currentTimeMillis() - start);
        return result;
    }
}

์ค‘์ฒฉ ์‚ฌ์šฉ:

Component real = new RealComponent();
Component message = new MessageDecorator(real);
Component time = new TimeDecorator(message);
client.execute(time);
// ํ˜ธ์ถœ ํ๋ฆ„: time โ†’ message โ†’ real โ†’ "data"
//          โ†’ "*****data*****" โ†’ ์‹œ๊ฐ„ ๋กœ๊ทธ

์ž๊ธฐ ์ ๊ฒ€

  • ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ๋ฌดํ•œํžˆ ์ค‘์ฒฉํ•  ์ˆ˜ ์žˆ๋Š”๊ฐ€?
  • ์ž๋ฐ” I/O์˜ BufferedReader, InputStreamReader๋„ ์ด ํŒจํ„ด์ธ๊ฐ€? (ํžŒํŠธ: YES)

Unit 4.3 โ€” ์˜๋„๋กœ ๊ตฌ๋ถ„ํ•˜๊ธฐ

์„ ์ˆ˜ ์ง€์‹: Unit 4.1, 4.2

ํ•ต์‹ฌ ํ†ต์ฐฐ

๋ชจ์–‘์€ ๊ฐ™๋‹ค, ์˜๋„๊ฐ€ ๋‹ค๋ฅด๋‹ค:

ํ”„๋ก์‹œ ํŒจํ„ด๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ํŒจํ„ด
์˜๋„์ ‘๊ทผ ์ œ์–ด๊ธฐ๋Šฅ ์ถ”๊ฐ€
์‚ฌ๋ก€์บ์‹œ, ๊ถŒํ•œ, ์ง€์—ฐ ๋กœ๋”ฉ๋กœ๊น…, ๋ฉ”์‹œ์ง€ ๊พธ๋ฏธ๊ธฐ, ์‹œ๊ฐ„ ์ธก์ •
ํด๋ผ์ด์–ธํŠธ ์ธ์ง€๋ณดํ†ต ๋ชจ๋ฆ„์•Œ ์ˆ˜๋„ ์žˆ์Œ
์ค‘์ฒฉ ์‚ฌ์šฉ๋“œ๋ฌผ์Œํ”ํ•จ

๊ตฌ๋ถ„ ๊ธฐ์ค€:

"ํ”„๋ก์‹œ๊ฐ€ ์ ‘๊ทผ ์ œ์–ด ๊ฐ€ ๋ชฉ์ ์ด๋ฉด ํ”„๋ก์‹œ ํŒจํ„ด, ์ƒˆ ๊ธฐ๋Šฅ ์ถ”๊ฐ€ ๊ฐ€ ๋ชฉ์ ์ด๋ฉด ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ํŒจํ„ด"

์ž๊ธฐ ์ ๊ฒ€

  • @Transactional ํ”„๋ก์‹œ๋Š” ์–ด๋А ์ชฝ์— ๊ฐ€๊นŒ์šด๊ฐ€?
  • ๊ฐ™์€ ์ฝ”๋“œ๊ฐ€ ๋‘ ํŒจํ„ด์œผ๋กœ ๋™์‹œ์— ๋ถ„๋ฅ˜๋  ์ˆ˜ ์žˆ๋Š”๊ฐ€?

๐Ÿ“š Phase 5 โ€” ๋™์  ํ”„๋ก์‹œ ๊ธฐ์ˆ  (Reflection / JDK / CGLIB)

๋ชฉํ‘œ: "ํ”„๋ก์‹œ ํด๋ž˜์Šค๋ฅผ 100๊ฐœ ๋งŒ๋“ค์–ด์•ผ ํ•˜๋Š” ๋ฌธ์ œ"๋ฅผ ์ž๋ฐ”์˜ ๋™์  ๊ธฐ์ˆ ๋กœ ํ•ด๊ฒฐํ•œ๋‹ค.

Unit 5.1 โ€” ์ˆ˜๋™ ํ”„๋ก์‹œ์˜ ๋ฌธ์ œ์™€ ๋ฆฌํ”Œ๋ ‰์…˜

์„ ์ˆ˜ ์ง€์‹: Phase 4

ํ•ต์‹ฌ ๋ฌธ์ œ

์ˆ˜๋™ ํ”„๋ก์‹œ์˜ ํ•œ๊ณ„:

  • ์ ์šฉ ๋Œ€์ƒ์ด 100๊ฐœ๋ฉด ํ”„๋ก์‹œ ํด๋ž˜์Šค๋„ 100๊ฐœ
  • ๋ชจ๋“  ํ”„๋ก์‹œ์˜ ์ฝ”๋“œ๊ฐ€ ๊ฑฐ์˜ ๊ฐ™์Œ (ํ˜ธ์ถœ ๋Œ€์ƒ๋งŒ ์ฐจ์ด)
  • ์œ ์ง€๋ณด์ˆ˜ ์ง€์˜ฅ

ํ•ด๊ฒฐ์˜ ์ถœ๋ฐœ์  โ€” ๋ฆฌํ”Œ๋ ‰์…˜:

๋ฆฌํ”Œ๋ ‰์…˜ ์‚ฌ์šฉ ์ „:

target.callA();  // ๋ฉ”์„œ๋“œ ์ด๋ฆ„์ด ์ฝ”๋“œ์— ๋ฐ•ํ˜€์žˆ์Œ
target.callB();  // ๋‹ค๋ฅธ ๋ฉ”์„œ๋“œ๋Š” ๋‹ค๋ฅธ ํ˜ธ์ถœ ์ฝ”๋“œ

๋ฆฌํ”Œ๋ ‰์…˜ ์‚ฌ์šฉ ํ›„:

Method methodA = classHello.getMethod("callA");
Method methodB = classHello.getMethod("callB");
dynamicCall(methodA, target);
dynamicCall(methodB, target);

private void dynamicCall(Method method, Object target) {
    method.invoke(target);  // ์–ด๋–ค ๋ฉ”์„œ๋“œ๋“  ํ˜ธ์ถœ ๊ฐ€๋Šฅ
}

๋ฆฌํ”Œ๋ ‰์…˜์˜ ์žฅ๋‹จ์ :

  • โœ… ๋ฉ”ํƒ€ ์ •๋ณด ๊ธฐ๋ฐ˜ ๋™์  ํ˜ธ์ถœ โ†’ ๋งค์šฐ ์œ ์—ฐ
  • โŒ ๋Ÿฐํƒ€์ž„ ๋™์ž‘ โ†’ ์ปดํŒŒ์ผ ์‹œ์  ์˜ค๋ฅ˜ ๊ฒ€์ถœ ๋ถˆ๊ฐ€

์ผ๋ฐ˜ ์ฝ”๋“œ์—์„œ ์“ฐ์ง€ ๋ง ๊ฒƒ โ€” ํ”„๋ ˆ์ž„์›Œํฌ ๊ฐœ๋ฐœ์šฉ

์ž๊ธฐ ์ ๊ฒ€

  • ๋ฆฌํ”Œ๋ ‰์…˜์ด ์ปดํŒŒ์ผ ์‹œ์  ์•ˆ์ „์„ฑ์„ ๊นจ๋Š” ์ด์œ ๋Š”?
  • JPA๊ฐ€ ์—”ํ‹ฐํ‹ฐ์˜ ๊ธฐ๋ณธ ์ƒ์„ฑ์ž๋ฅผ ์š”๊ตฌํ•˜๋Š” ์ด์œ ์™€ ๊ด€๋ จ์ด ์žˆ๋Š”๊ฐ€? (ํžŒํŠธ: YES)

Unit 5.2 โ€” JDK ๋™์  ํ”„๋ก์‹œ (์ธํ„ฐํŽ˜์ด์Šค ๊ธฐ๋ฐ˜)

์„ ์ˆ˜ ์ง€์‹: Unit 5.1

ํ•ต์‹ฌ ๊ฐœ๋…

"ํ”„๋ก์‹œ ํด๋ž˜์Šค๋ฅผ ๋Ÿฐํƒ€์ž„์— ์ž๋™ ์ƒ์„ฑ"

์ „์ œ ์กฐ๊ฑด: ์ธํ„ฐํŽ˜์ด์Šค ํ•„์ˆ˜

InvocationHandler ์ธํ„ฐํŽ˜์ด์Šค:

public interface InvocationHandler {
    Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
}

๊ตฌํ˜„ ์˜ˆ์‹œ โ€” ์‹œ๊ฐ„ ์ธก์ • ํ”„๋ก์‹œ:

public class TimeInvocationHandler implements InvocationHandler {
    private final Object target;
    
    public TimeInvocationHandler(Object target) {
        this.target = target;
    }
    
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        long start = System.currentTimeMillis();
        Object result = method.invoke(target, args);  // ์‹ค์ œ ํ˜ธ์ถœ
        log.info("time={}ms", System.currentTimeMillis() - start);
        return result;
    }
}

ํ”„๋ก์‹œ ์ƒ์„ฑ:

AInterface target = new AImpl();
TimeInvocationHandler handler = new TimeInvocationHandler(target);

AInterface proxy = (AInterface) Proxy.newProxyInstance(
    AInterface.class.getClassLoader(),
    new Class[]{AInterface.class},
    handler
);

proxy.call();  // ๋™์  ํ”„๋ก์‹œ๊ฐ€ ๊ฐ€๋กœ์ฑ”
// ์ถœ๋ ฅ: proxyClass=class com.sun.proxy.$Proxy1

ํ•ต์‹ฌ ํ†ต์ฐฐ:

  • AImpl 100๊ฐœ์—ฌ๋„ InvocationHandler 1๊ฐœ๋กœ ์ถฉ๋ถ„
  • ํ”„๋ก์‹œ ํด๋ž˜์Šค๋Š” JDK๊ฐ€ ๋™์  ์ƒ์„ฑ ($Proxy1, $Proxy2...)

์ž๊ธฐ ์ ๊ฒ€

  • JDK ๋™์  ํ”„๋ก์‹œ๊ฐ€ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์š”๊ตฌํ•˜๋Š” ์ด์œ ๋Š”? (ํžŒํŠธ: Proxy.newProxyInstance๊ฐ€ ๋ฐ›๋Š” ๋งค๊ฐœ๋ณ€์ˆ˜)
  • 5์ฃผ์ฐจ์˜ ์–ด๋–ค ๋””์ž์ธ ํŒจํ„ด์ด ์—ฌ๊ธฐ ์ ์šฉ๋๋Š”๊ฐ€?

Unit 5.3 โ€” CGLIB (๊ตฌ์ฒด ํด๋ž˜์Šค ๊ธฐ๋ฐ˜)

์„ ์ˆ˜ ์ง€์‹: Unit 5.2

ํ•ต์‹ฌ ๊ฐœ๋…

JDK ๋™์  ํ”„๋ก์‹œ์˜ ํ•œ๊ณ„:

  • ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ๋ฐ˜๋“œ์‹œ ํ•„์š”
  • ๊ตฌ์ฒด ํด๋ž˜์Šค๋งŒ ์žˆ์œผ๋ฉด ์‚ฌ์šฉ ๋ถˆ๊ฐ€

CGLIB (Code Generator Library):

  • ๋ฐ”์ดํŠธ์ฝ”๋“œ ์กฐ์ž‘ ์œผ๋กœ ๋™์  ํด๋ž˜์Šค ์ƒ์„ฑ
  • ์ธํ„ฐํŽ˜์ด์Šค ์—†์–ด๋„ OK โ€” ๊ตฌ์ฒด ํด๋ž˜์Šค ์ƒ์†
  • Spring ํ”„๋ ˆ์ž„์›Œํฌ ๋‚ด๋ถ€์— ํฌํ•จ๋˜์–ด ์žˆ์Œ

๋น„๊ต:

JDK ๋™์  ํ”„๋ก์‹œCGLIB
์ „์ œ์ธํ„ฐํŽ˜์ด์Šค ํ•„์š”๊ตฌ์ฒด ํด๋ž˜์Šค๋งŒ์œผ๋กœ OK
๋ฐฉ์‹์ธํ„ฐํŽ˜์ด์Šค ๊ตฌํ˜„ํด๋ž˜์Šค ์ƒ์†
ํ•ธ๋“ค๋ŸฌInvocationHandlerMethodInterceptor
๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌJDK ํ‘œ์ค€์™ธ๋ถ€ (Spring ํฌํ•จ)

์‹ค๋ฌด์—์„œ ์ง์ ‘ ์‚ฌ์šฉ?:

  • ๊ฑฐ์˜ ์•ˆ ํ•จ
  • Spring์˜ ProxyFactory ๊ฐ€ ๋‘˜์„ ํ†ตํ•ฉ (๋‹ค์Œ Phase)

์ž๊ธฐ ์ ๊ฒ€

  • CGLIB๊ฐ€ ๊ตฌ์ฒด ํด๋ž˜์Šค๋กœ๋„ ์ž‘๋™ํ•˜๋Š” ์ด์œ ๋Š”? (ํžŒํŠธ: ์ƒ์†)
  • final ํด๋ž˜์Šค์— CGLIB์„ ์ ์šฉํ•  ์ˆ˜ ์žˆ๋Š”๊ฐ€? (ํžŒํŠธ: NO, ์ƒ์† ๋ถˆ๊ฐ€)

๐Ÿ“š Phase 6 โ€” ProxyFactory: ์Šคํ”„๋ง์˜ ํ†ตํ•ฉ ์ถ”์ƒํ™” (โ˜… 8์ฃผ์ฐจ ์ •์ )

๋ชฉํ‘œ: JDK ๋™์  ํ”„๋ก์‹œ์™€ CGLIB์˜ ๋ถ„๊ธฐ๋ฅผ Spring์ด ์–ด๋–ป๊ฒŒ ํ†ตํ•ฉํ–ˆ๋Š”์ง€, ๊ทธ๋ฆฌ๊ณ  ๊ทธ ์œ„์— ์–ด๋–ป๊ฒŒ Pointcut/Advice/Advisor ์ถ”์ƒํ™”๋ฅผ ์Œ“์•˜๋Š”์ง€๋ฅผ ๋ณธ๋‹ค.

Unit 6.1 โ€” ProxyFactory โ€” JDK/CGLIB ํ†ตํ•ฉ

์„ ์ˆ˜ ์ง€์‹: Phase 5

ํ•ต์‹ฌ ๊ฐœ๋…

๋ฌธ์ œ:

  • ์ธํ„ฐํŽ˜์ด์Šค ์žˆ์œผ๋ฉด JDK ๋™์  ํ”„๋ก์‹œ
  • ๊ตฌ์ฒด ํด๋ž˜์Šค๋งŒ ์žˆ์œผ๋ฉด CGLIB
  • โ†’ ๋‘ ๊ธฐ์ˆ ์„ ๋งค๋ฒˆ ์„ ํƒํ•ด์•ผ ํ•จ

ProxyFactory์˜ ํ•ด๊ฒฐ:

ServiceInterface target = new ServiceImpl();
ProxyFactory proxyFactory = new ProxyFactory(target);
proxyFactory.addAdvice(new TimeAdvice());

ServiceInterface proxy = (ServiceInterface) proxyFactory.getProxy();
// โ†’ ์ž๋™์œผ๋กœ JDK ๋™์  ํ”„๋ก์‹œ ๋˜๋Š” CGLIB ์„ ํƒ

์ž๋™ ์„ ํƒ ๊ทœ์น™:

  • ์ธํ„ฐํŽ˜์ด์Šค ์žˆ์Œ โ†’ JDK ๋™์  ํ”„๋ก์‹œ
  • ๊ตฌ์ฒด ํด๋ž˜์Šค๋งŒ โ†’ CGLIB
  • ์˜ต์…˜์œผ๋กœ ๊ฐ•์ œ ๊ฐ€๋Šฅ (proxyTargetClass=true โ†’ ๊ฐ•์ œ CGLIB)

Spring Boot์˜ ๊ธฐ๋ณธ ์„ค์ •:

Spring Boot๋Š” AOP ์ ์šฉ ์‹œ ๊ธฐ๋ณธ์ ์œผ๋กœ proxyTargetClass=true โ†’ ํ•ญ์ƒ CGLIB

์ž๊ธฐ ์ ๊ฒ€

  • Spring Boot๊ฐ€ CGLIB์„ ๊ธฐ๋ณธ์œผ๋กœ ์„ ํƒํ•œ ์ด์œ ๋Š”? (ํžŒํŠธ: ์ธํ„ฐํŽ˜์ด์Šค ์—†๋Š” ํด๋ž˜์Šค๋„ ์ผ๊ด€์„ฑ ์žˆ๊ฒŒ)
  • ProxyFactory๊ฐ€ 5์ฃผ์ฐจ์˜ ์–ด๋–ค ๋””์ž์ธ ํŒจํ„ด์ธ๊ฐ€? (ํžŒํŠธ: ํŒฉํ† ๋ฆฌ)

Unit 6.2 โ€” Advice ์ถ”์ƒํ™”

์„ ์ˆ˜ ์ง€์‹: Unit 6.1

ํ•ต์‹ฌ ๊ฐœ๋…

๋ฌธ์ œ:

  • JDK๋Š” InvocationHandler, CGLIB๋Š” MethodInterceptor
  • ๋‘ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๋‘˜ ๋‹ค ๊ตฌํ˜„ํ•˜๋ฉด ์ค‘๋ณต

Advice์˜ ๋“ฑ์žฅ:

  • ๋‘˜์„ ๊ฐœ๋…์ ์œผ๋กœ ์ถ”์ƒํ™” ํ•œ ์ธํ„ฐํŽ˜์ด์Šค
  • ๊ฐœ๋ฐœ์ž๋Š” Advice๋งŒ ๊ตฌํ˜„ํ•˜๋ฉด ๋จ
  • ProxyFactory๊ฐ€ ๋‚ด๋ถ€์—์„œ ๋‘˜์„ ๋ณ€ํ™˜
// org.aopalliance.intercept.MethodInterceptor ๊ตฌํ˜„
public class TimeAdvice implements MethodInterceptor {
    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        long start = System.currentTimeMillis();
        Object result = invocation.proceed();  // ์‹ค์ œ ํ˜ธ์ถœ
        log.info("time={}ms", System.currentTimeMillis() - start);
        return result;
    }
}

โš ๏ธ ํŒจํ‚ค์ง€ ์ฃผ์˜:

  • org.aopalliance.intercept.MethodInterceptor (Advice์šฉ โœ…)
  • org.springframework.cglib.proxy.MethodInterceptor (CGLIB ์ง์ ‘ ์‚ฌ์šฉ์šฉ)

์ƒ์† ๊ตฌ์กฐ:

Advice โ† Interceptor โ† MethodInterceptor (org.aopalliance)

์ž๊ธฐ ์ ๊ฒ€

  • "๊ฐœ๋ฐœ์ž๋Š” ํ”„๋ก์‹œ ์ƒ์„ฑ์€ ProxyFactory์—, ๋กœ์ง์€ Advice์—" ์˜๋ฏธ๋Š”?
  • 6์ฃผ์ฐจ JdbcTemplate์˜ RowMapper์™€ Advice์˜ ๊ณตํ†ต์ ์€? (ํžŒํŠธ: ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค ์ถ”์ƒํ™”)

Unit 6.3 โ€” Pointcut + Advice = Advisor

์„ ์ˆ˜ ์ง€์‹: Unit 6.2

ํ•ต์‹ฌ ๊ฐœ๋…

3๋Œ€ ๊ฐœ๋… ์ •๋ฆฌ โญ :

์šฉ์–ด์˜๋ฏธ
Pointcut"์–ด๋””์—" ์ ์šฉํ• ์ง€ (ํ•„ํ„ฐ๋ง)
Advice"์–ด๋–ค ๋กœ์ง"์„ ์ ์šฉํ• ์ง€ (๋ถ€๊ฐ€ ๊ธฐ๋Šฅ)
Advisor"Pointcut + Advice" (์–ด๋””์— + ์–ด๋–ค ๋กœ์ง)

Pointcut ์‚ฌ์šฉ ์˜ˆ์‹œ:

NameMatchMethodPointcut pointcut = new NameMatchMethodPointcut();
pointcut.setMappedNames("save");  // save ๋ฉ”์„œ๋“œ๋งŒ ๋งค์นญ

DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor(pointcut, new TimeAdvice());

proxyFactory.addAdvisor(advisor);
ServiceInterface proxy = (ServiceInterface) proxyFactory.getProxy();

proxy.save();   // โœ… Advice ์ ์šฉ๋จ
proxy.find();   // โŒ Advice ์•ˆ ๋จ

์Šคํ”„๋ง ๊ธฐ๋ณธ Pointcut ์ข…๋ฅ˜:

  • NameMatchMethodPointcut: ๋ฉ”์„œ๋“œ ์ด๋ฆ„ ๋งค์นญ
  • JdkRegexpMethodPointcut: ์ •๊ทœํ‘œํ˜„์‹
  • TruePointcut: ํ•ญ์ƒ ์ฐธ
  • AnnotationMatchingPointcut: ์–ด๋…ธํ…Œ์ด์…˜ ๋งค์นญ
  • AspectJExpressionPointcut: AspectJ ํ‘œํ˜„์‹ โญ (์‹ค๋ฌด ํ‘œ์ค€)

์ž๊ธฐ ์ ๊ฒ€

  • @Transactional์˜ Pointcut์€ ์–ด๋–ค ํ‘œํ˜„์‹์ด ๋  ์ˆ˜ ์žˆ์„๊นŒ?
  • ProxyFactory์— Advisor ์—†์ด Advice๋งŒ ๋“ฑ๋กํ•˜๋ฉด? (ํžŒํŠธ: ๋ชจ๋“  ๋ฉ”์„œ๋“œ์— ์ ์šฉ)

Unit 6.4 โ€” ํ•˜๋‚˜์˜ ํ”„๋ก์‹œ, ์—ฌ๋Ÿฌ ์–ด๋“œ๋ฐ”์ด์ €

์„ ์ˆ˜ ์ง€์‹: Unit 6.3

ํ•ต์‹ฌ ๊ฐœ๋…

์—ฌ๋Ÿฌ ๋ถ€๊ฐ€ ๊ธฐ๋Šฅ์„ ํ•œ ๊ฐ์ฒด์—:

ProxyFactory proxyFactory = new ProxyFactory(target);
proxyFactory.addAdvisor(advisor2);  // ๋จผ์ € ๋“ฑ๋ก
proxyFactory.addAdvisor(advisor1);  // ๋‚˜์ค‘ ๋“ฑ๋ก

ServiceInterface proxy = (ServiceInterface) proxyFactory.getProxy();
proxy.save();
// ํ˜ธ์ถœ ํ๋ฆ„: proxy โ†’ advisor2 โ†’ advisor1 โ†’ target

์ค‘์š” โ€” Spring AOP ์ตœ์ ํ™” โญ :

"์Šคํ”„๋ง AOP๋Š” target ๋งˆ๋‹ค ํ•˜๋‚˜์˜ ํ”„๋ก์‹œ๋งŒ ์ƒ์„ฑํ•œ๋‹ค"

์—ฌ๋Ÿฌ AOP๊ฐ€ ๋™์‹œ ์ ์šฉ๋˜์–ด๋„ โ†’ 1๊ฐœ ํ”„๋ก์‹œ + N๊ฐœ ์–ด๋“œ๋ฐ”์ด์ €

์˜๋ฏธ:

  • ๋ฉ”๋ชจ๋ฆฌ ํšจ์œจ
  • ์„ฑ๋Šฅ ์ตœ์ ํ™”
  • ํ˜ธ์ถœ ์ˆœ์„œ๋Š” ๋“ฑ๋ก ์ˆœ์„œ

์ž๊ธฐ ์ ๊ฒ€

  • ๋งŒ์•ฝ ์–ด๋“œ๋ฐ”์ด์ €๋งˆ๋‹ค ๋ณ„๋„ ํ”„๋ก์‹œ๋ฅผ ๋งŒ๋“ ๋‹ค๋ฉด 100๊ฐœ AOP ์ ์šฉ ์‹œ ์–ด๋–ป๊ฒŒ ๋ ๊นŒ?
  • ์–ด๋“œ๋ฐ”์ด์ €์˜ ์ˆœ์„œ๋ฅผ ๋ช…์‹œ์ ์œผ๋กœ ์ œ์–ดํ•˜๋ ค๋ฉด? (ํžŒํŠธ: @Order)

๐ŸŒŸ Part B โ€” 9์ฃผ์ฐจ: Spring AOP ์‹ค์ „

๐Ÿ“š Phase 7 โ€” ๋นˆ ํ›„์ฒ˜๋ฆฌ๊ธฐ์™€ ์ž๋™ ํ”„๋ก์‹œ ์ƒ์„ฑ๊ธฐ

๋ชฉํ‘œ: ์ปดํฌ๋„ŒํŠธ ์Šค์บ”๋œ ๋นˆ์—๋„ ํ”„๋ก์‹œ๋ฅผ ์ ์šฉํ•˜๋Š” ๋ฉ”์ปค๋‹ˆ์ฆ˜์„ ์ดํ•ดํ•œ๋‹ค.

Unit 7.1 โ€” ์ˆ˜๋™ ๋“ฑ๋ก์˜ ํ•œ๊ณ„ (์ปดํฌ๋„ŒํŠธ ์Šค์บ” ๋ฌธ์ œ)

์„ ์ˆ˜ ์ง€์‹: Phase 6

๋‘ ๊ฐ€์ง€ ํฐ ๋ฌธ์ œ

๋ฌธ์ œ 1 โ€” ๋„ˆ๋ฌด ๋งŽ์€ ์„ค์ •:

  • ๋นˆ 100๊ฐœ์— ํ”„๋ก์‹œ ์ ์šฉ โ†’ 100๊ฐœ ํ”„๋ก์‹œ ์ƒ์„ฑ ์ฝ”๋“œ
  • "์„ค์ • ์ง€์˜ฅ"

๋ฌธ์ œ 2 โ€” ์ปดํฌ๋„ŒํŠธ ์Šค์บ”:

  • @Service, @Repository ๋“ฑ์œผ๋กœ ์ž๋™ ๋“ฑ๋ก๋œ ๋นˆ
  • ์ด๋ฏธ ์‹ค์ œ ๊ฐ์ฒด ๊ฐ€ ์ปจํ…Œ์ด๋„ˆ์— ๋“ฑ๋ก๋จ
  • ํ”„๋ก์‹œ๋กœ ๊ต์ฒดํ•  ๋ฐฉ๋ฒ•์ด ์—†์Œ

โ†’ ๋นˆ ๋“ฑ๋ก์„ ๊ฐ€๋กœ์ฑ„์„œ ํ”„๋ก์‹œ๋กœ ๋ฐ”๊ฟ”์น˜๊ธฐ ํ•ด์•ผ ํ•œ๋‹ค

์ž๊ธฐ ์ ๊ฒ€

  • 5์ฃผ์ฐจ์˜ @Component ์ปดํฌ๋„ŒํŠธ ์Šค์บ” ๋ฉ”์ปค๋‹ˆ์ฆ˜๊ณผ ์ถฉ๋Œํ•˜๋Š”๊ฐ€?
  • "๋นˆ ํ›„์ฒ˜๋ฆฌ๊ธฐ"๋ผ๋Š” ์ด๋ฆ„์—์„œ "ํ›„"๋Š” ๋ฌด์—‡ ํ›„์ผ๊นŒ?

Unit 7.2 โ€” BeanPostProcessor โ€” ๋นˆ ์กฐ์ž‘ ํ›„ํ‚น

์„ ์ˆ˜ ์ง€์‹: Unit 7.1

ํ•ต์‹ฌ ๊ฐœ๋…

BeanPostProcessor ์ธํ„ฐํŽ˜์ด์Šค:

public interface BeanPostProcessor {
    Object postProcessBeforeInitialization(Object bean, String beanName);
    Object postProcessAfterInitialization(Object bean, String beanName);
}

์˜ˆ์‹œ โ€” A๋ฅผ B๋กœ ๋ฐ”๊ฟ”์น˜๊ธฐ:

public class AToBPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) {
        if (bean instanceof A) {
            return new B();  // A ๋Œ€์‹  B ๋ฐ˜ํ™˜
        }
        return bean;
    }
}

// ๊ฒฐ๊ณผ
B b = applicationContext.getBean("beanA", B.class);  // beanA ์ด๋ฆ„์œผ๋กœ B ๋ฐ˜ํ™˜!

์˜์˜:

  • ๋นˆ์„ ์ปจํ…Œ์ด๋„ˆ ๋“ฑ๋ก ์ง์ „์— ๊ฐ€๋กœ์ฑ„๊ธฐ
  • ๊ฐ์ฒด๋ฅผ ์กฐ์ž‘/๊ต์ฒด ๊ฐ€๋Šฅ
  • โ†’ ๋นˆ์„ ํ”„๋ก์‹œ๋กœ ๋ฐ”๊ฟ”์น˜๊ธฐ ๊ฐ€๋Šฅ

์ž๊ธฐ ์ ๊ฒ€

  • ์ผ๋ฐ˜์ ์ธ ๋นˆ ๋“ฑ๋ก ํ๋ฆ„์—์„œ ์–ด๋–ค ๋‹จ๊ณ„์— ๋ผ์–ด๋“œ๋Š”๊ฐ€?
  • ์ด๊ฒŒ ๊ฐ€๋Šฅํ•œ ์ด์œ ๋Š”? (ํžŒํŠธ: ApplicationContext์˜ ๋ผ์ดํ”„์‚ฌ์ดํด)

Unit 7.3 โ€” AnnotationAwareAspectJAutoProxyCreator

์„ ์ˆ˜ ์ง€์‹: Unit 7.2

ํ•ต์‹ฌ ๊ฐœ๋…

์Šคํ”„๋ง์ด ์ œ๊ณตํ•˜๋Š” ์ž๋™ ํ”„๋ก์‹œ ์ƒ์„ฑ๊ธฐ:

  • ์˜์กด์„ฑ: spring-boot-starter-aop
  • Spring Boot๊ฐ€ ์ž๋™ ๋“ฑ๋ก
  • = ๋นˆ ํ›„์ฒ˜๋ฆฌ๊ธฐ

๋™์ž‘:
1. ์Šคํ”„๋ง ๋นˆ์œผ๋กœ ๋“ฑ๋ก๋œ ๋ชจ๋“  Advisor ๋“ค์„ ์ž๋™์œผ๋กœ ์ฐพ์Œ
2. ๊ฐ ๋นˆ์— ๋Œ€ํ•ด Advisor์˜ Pointcut์œผ๋กœ ๋งค์นญ ๊ฒ€์‚ฌ
3. ๋งค์นญ๋˜๋ฉด ํ•ด๋‹น ๋นˆ์„ ํ”„๋ก์‹œ๋กœ ๊ต์ฒด

@Bean
public Advisor advisor3(LogTrace logTrace) {
    AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
    pointcut.setExpression("execution(* hello.proxy.app..*(..)) && !execution(* hello.proxy.app..noLog(..))");
    LogTraceAdvice advice = new LogTraceAdvice(logTrace);
    return new DefaultPointcutAdvisor(pointcut, advice);
}

์ด๋ฆ„์˜ ์˜๋ฏธ:

  • AnnotationAwareAspectJAutoProxyCreator
  • AutoProxyCreator: ์ž๋™ ํ”„๋ก์‹œ ์ƒ์„ฑ
  • AspectJ: AspectJ ํ‘œํ˜„์‹ ์ง€์›
  • AnnotationAware: ์–ด๋…ธํ…Œ์ด์…˜ ์ธ์‹ (@Aspect)

์ž๊ธฐ ์ ๊ฒ€

  • "์Šคํ”„๋ง ๋นˆ์œผ๋กœ ๋“ฑ๋ก๋œ Advisor"๋ฅผ ์–ด๋–ป๊ฒŒ ๋“ฑ๋กํ•˜๋Š”๊ฐ€?
  • noLog() ๋ฉ”์„œ๋“œ๋ฅผ ์ œ์™ธ์‹œํ‚จ ํ‘œํ˜„์‹์˜ ์˜๋ฏธ๋Š”?

๐Ÿ“š Phase 8 โ€” @Aspect์™€ AOP ์šฉ์–ด ์™„์ „ ์ •๋ฆฌ

๋ชฉํ‘œ: ์‹ค๋ฌด์—์„œ ๊ฐ€์žฅ ๋งŽ์ด ์“ฐ๋Š” @Aspect ์–ด๋…ธํ…Œ์ด์…˜ ๋ฐฉ์‹์„ ๋งˆ์Šคํ„ฐํ•˜๊ณ , AOP ์šฉ์–ด๋ฅผ ์ •ํ™•ํžˆ ์žก๋Š”๋‹ค.

Unit 8.1 โ€” @Aspect โ€” ์–ด๋“œ๋ฐ”์ด์ € ์ž๋™ ์ƒ์„ฑ

์„ ์ˆ˜ ์ง€์‹: Phase 7

ํ•ต์‹ฌ ๊ฐœ๋…

@Aspect ์˜ ์—ญํ• :

  • AspectJ ํ”„๋กœ์ ํŠธ์˜ ์–ด๋…ธํ…Œ์ด์…˜
  • Spring์ด ์ฐจ์šฉํ•ด์„œ ์‚ฌ์šฉ
  • @Aspect ํด๋ž˜์Šค โ†’ Advisor ์ž๋™ ๋ณ€ํ™˜

์˜ˆ์‹œ:

@Slf4j
@Aspect
public class LogTraceAspect {
    private final LogTrace logTrace;
    
    public LogTraceAspect(LogTrace logTrace) {
        this.logTrace = logTrace;
    }
    
    @Around("execution(* hello.proxy.app..*(..))")
    public Object execute(ProceedingJoinPoint joinPoint) throws Throwable {
        TraceStatus status = null;
        try {
            String message = joinPoint.getSignature().toShortString();
            status = logTrace.begin(message);
            Object result = joinPoint.proceed();  // ์‹ค์ œ ํ˜ธ์ถœ
            logTrace.end(status);
            return result;
        } catch (Exception e) {
            logTrace.exception(status, e);
            throw e;
        }
    }
}

๊ตฌ์„ฑ ์š”์†Œ:

  • @Aspect: "์ด ํด๋ž˜์Šค๋Š” ์–ด๋“œ๋ฐ”์ด์ € ๋ณ€ํ™˜ ๋Œ€์ƒ"
  • @Around: ์–ด๋“œ๋ฐ”์ด์Šค + ํฌ์ธํŠธ์ปท
  • ProceedingJoinPoint: MethodInvocation์˜ AOP ๋ฒ„์ „
  • joinPoint.proceed(): target ํ˜ธ์ถœ

โš ๏ธ @Aspect๋Š” ์ž๋™ ๋นˆ ๋“ฑ๋ก์ด ์•„๋‹˜:

  • @Aspect๋Š” ๋‹จ์ˆœํ•œ ํ‘œ์‹
  • ๋ณ„๋„๋กœ ๋นˆ ๋“ฑ๋ก ํ•„์š”
  • ๋ฐฉ๋ฒ•: @Bean, @Component, @Import

์ž๊ธฐ ์ ๊ฒ€

  • @Aspect ํด๋ž˜์Šค๋ฅผ ๋นˆ์œผ๋กœ ๋“ฑ๋กํ•˜์ง€ ์•Š์œผ๋ฉด?
  • ProceedingJoinPoint์™€ MethodInvocation์˜ ์ฐจ์ด๋Š”? (ํžŒํŠธ: AspectJ vs Spring AOP)

Unit 8.2 โ€” AOP ๋“ฑ์žฅ ๋ฐฐ๊ฒฝ ์ •๋ฆฌ

์„ ์ˆ˜ ์ง€์‹: Unit 8.1, Phase 1

ํ•ต์‹ฌ ํ†ต์ฐฐ

OOP์˜ ํ•œ๊ณ„:

  • ํ•ต์‹ฌ ๊ธฐ๋Šฅ๊ณผ ๋ถ€๊ฐ€ ๊ธฐ๋Šฅ (๋กœ๊ทธ, ํŠธ๋žœ์žญ์…˜) ๋ถ„๋ฆฌ๊ฐ€ ์–ด๋ ค์›€
  • ๋ถ€๊ฐ€ ๊ธฐ๋Šฅ์„ 100๊ฐœ ํด๋ž˜์Šค์— ์ ์šฉ โ†’ 100๊ตฐ๋ฐ ์ˆ˜์ •
  • ๋ถ€๊ฐ€ ๊ธฐ๋Šฅ ์œ„์น˜ ๋ณ€๊ฒฝ โ†’ ๋˜ 100๊ตฐ๋ฐ ์ˆ˜์ •

AOP์˜ ๋‹ต:

"๋ถ€๊ฐ€ ๊ธฐ๋Šฅ + ๋ถ€๊ฐ€ ๊ธฐ๋Šฅ์„ ์–ด๋””์— ์ ์šฉํ• ์ง€ ์˜ ์„ ํƒ์„ ํ•ฉ์ณ์„œ ํ•˜๋‚˜์˜ ๋ชจ๋“ˆ๋กœ ๋งŒ๋“ ๋‹ค"

๊ทธ๊ฒŒ Aspect = ๊ด€์ 

์ค‘์š”ํ•œ ๋ช…์ œ:

AOP๋Š” OOP๋ฅผ ๋Œ€์ฒดํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋‹ค.
OOP์˜ ๋ถ€์กฑํ•œ ๋ถ€๋ถ„(ํšก๋‹จ ๊ด€์‹ฌ์‚ฌ)์„ ๋ณด์กฐํ•œ๋‹ค.

์ž๊ธฐ ์ ๊ฒ€

  • "ํšก๋‹จ ๊ด€์‹ฌ์‚ฌ(Cross-cutting concerns)"์˜ ์˜๋ฏธ๋Š”?
  • AOP๋ฅผ ๋‚จ์šฉํ•˜๋ฉด ์–ด๋–ค ๋ฌธ์ œ๊ฐ€? (ํžŒํŠธ: ํ๋ฆ„ ์ถ”์  ์–ด๋ ค์›€, ๋””๋ฒ„๊น… ๋‚œ์ด๋„)

Unit 8.3 โ€” AspectJ vs Spring AOP

์„ ์ˆ˜ ์ง€์‹: Unit 8.2

ํ•ต์‹ฌ ๋น„๊ต

AspectJ ํ”„๋ ˆ์ž„์›Œํฌ:

  • AOP์˜ ๋Œ€ํ‘œ์  ๊ตฌํ˜„
  • ์ž์ฒด ์ปดํŒŒ์ผ๋Ÿฌ, ์ž์ฒด ๋ฌธ๋ฒ•
  • ๊ธฐ๋Šฅ ๊ฐ•๋ ฅ

Spring AOP:

  • AspectJ ๋ฌธ๋ฒ•๋งŒ ์ฐจ์šฉ
  • ํ”„๋ก์‹œ ๋ฐฉ์‹์œผ๋กœ ๋™์ž‘
  • ๋ณ„๋„ ์ปดํŒŒ์ผ๋Ÿฌ ๋ถˆํ•„์š”

AOP ์ ์šฉ ์‹œ์  3๊ฐ€์ง€:

์‹œ์ ๋ฐฉ์‹๋ˆ„๊ฐ€ ์‚ฌ์šฉ?
์ปดํŒŒ์ผ ์‹œ์ ์‹ค์ œ ์ฝ”๋“œ์— ๋ถ€๊ฐ€ ๊ธฐ๋Šฅ ์ฝ”๋“œ ์‚ฝ์ž…AspectJ ์ง์ ‘
ํด๋ž˜์Šค ๋กœ๋”ฉ ์‹œ์ ํด๋ž˜์Šค ๋กœ๋”ฉ ์‹œ ์ฝ”๋“œ ๋ณ€๊ฒฝAspectJ ์ง์ ‘
๋Ÿฐํƒ€์ž„ ์‹œ์ ํ”„๋ก์‹œ๋กœ ๋ถ€๊ฐ€ ๊ธฐ๋Šฅ ์ ์šฉSpring AOP โญ

์‹ค๋ฌด ๊ฒฐ๋ก :

"Spring AOP๋งŒ์œผ๋กœ ๋Œ€๋ถ€๋ถ„ ํ•ด๊ฒฐ ๊ฐ€๋Šฅ. AspectJ ์ง์ ‘ ์‚ฌ์šฉ์€ ์•ˆ ํ•ด๋„ ๋จ"

์ž๊ธฐ ์ ๊ฒ€

  • Spring AOP๊ฐ€ ํ•ญ์ƒ ํ”„๋ก์‹œ๋ฅผ ๊ฑฐ์ณ์•ผ ํ•œ๋‹ค๋Š” ๊ฒŒ ์–ด๋–ค ํ•œ๊ณ„๋กœ ์ด์–ด์ง€๋Š”๊ฐ€? (ํžŒํŠธ: internal call)
  • AspectJ ์ปดํŒŒ์ผ ์‹œ์  ๋ฐฉ์‹์€ internal call ๋ฌธ์ œ๊ฐ€ ์žˆ๋Š”๊ฐ€? (ํžŒํŠธ: NO)

Unit 8.4 โ€” AOP ํ•ต์‹ฌ ์šฉ์–ด

์„ ์ˆ˜ ์ง€์‹: Phase 7~8

ํ•ต์‹ฌ ์šฉ์–ด 7๊ฐ€์ง€ โญ :

์šฉ์–ด์˜๋ฏธ์˜ˆ์‹œ
์กฐ์ธ ํฌ์ธํŠธ(Join point)๋ถ€๊ฐ€ ๊ธฐ๋Šฅ์„ ์ ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๋ชจ๋“  ์ง€์ ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ, ์ƒ์„ฑ์ž, ํ•„๋“œ ์ ‘๊ทผ
ํฌ์ธํŠธ์ปท(Pointcut)์กฐ์ธ ํฌ์ธํŠธ ์ค‘ ์‹ค์ œ ์ ์šฉํ•  ๊ณณ์„ ์„ ํƒexecution(* hello..*Service.*(..))
์–ด๋“œ๋ฐ”์ด์Šค(Advice)์ ์šฉํ•  ๋ถ€๊ฐ€ ๊ธฐ๋Šฅ ์ฝ”๋“œ@Around ๋ฉ”์„œ๋“œ
์• ์ŠคํŽ™ํŠธ(Aspect)ํฌ์ธํŠธ์ปท + ์–ด๋“œ๋ฐ”์ด์Šค์˜ ๋ชจ๋“ˆ@Aspect ํด๋ž˜์Šค
ํƒ€๊ฒŸ(Target)๋ถ€๊ฐ€ ๊ธฐ๋Šฅ์ด ์ ์šฉ๋˜๋Š” ์‹ค์ œ ๊ฐ์ฒดOrderService ์ธ์Šคํ„ด์Šค
์œ„๋น™(Weaving)ํฌ์ธํŠธ์ปท์„ ํ†ตํ•ด ์–ด๋“œ๋ฐ”์ด์Šค๋ฅผ ๊ฒฐํ•ฉํ”„๋ก์‹œ ์ƒ์„ฑ ์‹œ
AOP ํ”„๋ก์‹œAOP ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•œ ํ”„๋ก์‹œJDK ๋™์  ํ”„๋ก์‹œ ๋˜๋Š” CGLIB

Spring AOP์˜ ํ•œ๊ณ„ โ€” ๋ฉ”์„œ๋“œ ์กฐ์ธ ํฌ์ธํŠธ๋งŒ:

  • ๋‹ค๋ฅธ AOP๋Š” ํ•„๋“œ ์ ‘๊ทผ, ์ƒ์„ฑ์ž๋„ ๊ฐ€๋Šฅ
  • Spring AOP๋Š” ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ๋งŒ ์ง€์›

์ž๊ธฐ ์ ๊ฒ€

  • "์กฐ์ธ ํฌ์ธํŠธ vs ํฌ์ธํŠธ์ปท"์˜ ์ฐจ์ด๋Š”? (ํžŒํŠธ: ํ›„์ž๊ฐ€ ๋ถ€๋ถ„์ง‘ํ•ฉ)
  • ์œ„๋น™์ด ์ผ์–ด๋‚˜๋Š” ์‹œ์ ์€ Spring AOP์—์„œ ์–ธ์ œ์ธ๊ฐ€? (ํžŒํŠธ: ๋นˆ ํ›„์ฒ˜๋ฆฌ๊ธฐ ์‹œ์ )

๐Ÿ“š Phase 9 โ€” Spring AOP ์‹ค์ „ ๊ตฌํ˜„ ํŒจํ„ด

๋ชฉํ‘œ: ์‹ค๋ฌด์—์„œ ๋งค์ผ ์“ฐ๋Š” ํŒจํ„ด๋“ค์„ ์†์— ์ตํžŒ๋‹ค.

Unit 9.1 โ€” @Around์™€ ProceedingJoinPoint

์„ ์ˆ˜ ์ง€์‹: Phase 8

ํ•ต์‹ฌ ๊ฐœ๋…

@Around โ€” ๊ฐ€์žฅ ๊ฐ•๋ ฅํ•œ ์–ด๋“œ๋ฐ”์ด์Šค:

  • ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ ์ „ํ›„ ๋ชจ๋‘ ๊ฐ€๋กœ์ฑ„๊ธฐ
  • ํ˜ธ์ถœ ์ž์ฒด๋ฅผ ๊ฑด๋„ˆ๋›ธ ์ˆ˜๋„ ์žˆ์Œ
  • ๋ฐ˜ํ™˜๊ฐ’/์˜ˆ์™ธ ๋ณ€ํ™˜ ๊ฐ€๋Šฅ
@Aspect
public class AspectV1 {
    @Around("execution(* hello.aop.order..*(..))")
    public Object doLog(ProceedingJoinPoint joinPoint) throws Throwable {
        log.info("[log] {}", joinPoint.getSignature());
        return joinPoint.proceed();  // ์‹ค์ œ ํ˜ธ์ถœ
    }
}

ProceedingJoinPoint์˜ ์ฃผ์š” ๋ฉ”์„œ๋“œ:

  • proceed(): target ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ
  • getSignature(): ํ˜ธ์ถœ๋œ ๋ฉ”์„œ๋“œ์˜ ์‹œ๊ทธ๋‹ˆ์ฒ˜
  • getArgs(): ์ „๋‹ฌ ์ธ์ž ๋ฐฐ์—ด
  • getTarget(): ์‹ค์ œ ๋Œ€์ƒ ๊ฐ์ฒด

์ž๊ธฐ ์ ๊ฒ€

  • proceed()๋ฅผ ํ˜ธ์ถœํ•˜์ง€ ์•Š์œผ๋ฉด? (ํžŒํŠธ: target ๋ฉ”์„œ๋“œ๊ฐ€ ์‹คํ–‰ ์•ˆ ๋จ)
  • proceed()๋ฅผ ๋‘ ๋ฒˆ ํ˜ธ์ถœํ•˜๋ฉด? (ํžŒํŠธ: ๋ฉ”์„œ๋“œ๊ฐ€ ๋‘ ๋ฒˆ ์‹คํ–‰)

Unit 9.2 โ€” @Pointcut์œผ๋กœ ๋ถ„๋ฆฌ

์„ ์ˆ˜ ์ง€์‹: Unit 9.1

ํ•ต์‹ฌ ๊ฐœ๋…

๋ฌธ์ œ: ๊ฐ™์€ ํฌ์ธํŠธ์ปท์„ ์—ฌ๋Ÿฌ ์–ด๋“œ๋ฐ”์ด์Šค์—์„œ ๋ฐ˜๋ณต ์ž‘์„ฑ โ†’ ์ค‘๋ณต

ํ•ด๊ฒฐ โ€” @Pointcut์œผ๋กœ ์‹œ๊ทธ๋‹ˆ์ฒ˜ ๋ถ„๋ฆฌ:

@Aspect
public class AspectV2 {
    @Pointcut("execution(* hello.aop.order..*(..))")
    private void allOrder() {}  // ์‹œ๊ทธ๋‹ˆ์ฒ˜๋งŒ (body ์—†์Œ)
    
    @Around("allOrder()")  // ์žฌ์‚ฌ์šฉ
    public Object doLog(ProceedingJoinPoint joinPoint) throws Throwable {
        log.info("[log] {}", joinPoint.getSignature());
        return joinPoint.proceed();
    }
}

๋ณ„๋„ ํด๋ž˜์Šค๋กœ ๋ถ„๋ฆฌ (์‹ค๋ฌด ํ‘œ์ค€):

public class Pointcuts {
    @Pointcut("execution(* hello.aop.order..*(..))")
    public void allOrder() {}
    
    @Pointcut("execution(* *..*Service.*(..))")
    public void allService() {}
    
    @Pointcut("allOrder() && allService()")  // ์กฐํ•ฉ
    public void orderAndService() {}
}

@Aspect
public class AspectV4Pointcut {
    @Around("hello.aop.order.aop.Pointcuts.allOrder()")
    public Object doLog(ProceedingJoinPoint joinPoint) throws Throwable { ... }
    
    @Around("hello.aop.order.aop.Pointcuts.orderAndService()")
    public Object doTransaction(ProceedingJoinPoint joinPoint) throws Throwable { ... }
}

ํฌ์ธํŠธ์ปท ํ‘œํ˜„์‹์˜ ์กฐํ•ฉ:

  • &&, ||, !

์ž๊ธฐ ์ ๊ฒ€

  • @Pointcut ๋ฉ”์„œ๋“œ์˜ body๊ฐ€ ๋น„์–ด์žˆ๋Š” ์ด์œ ๋Š”?
  • ํฌ์ธํŠธ์ปท ๋ถ„๋ฆฌ๊ฐ€ 5์ฃผ์ฐจ ์–ด๋–ค ์›์น™์˜ ์ ์šฉ์ธ๊ฐ€? (ํžŒํŠธ: DRY, ๊ด€์‹ฌ์‚ฌ ๋ถ„๋ฆฌ)

Unit 9.3 โ€” ์–ด๋“œ๋ฐ”์ด์Šค ์ข…๋ฅ˜ 5๊ฐ€์ง€

์„ ์ˆ˜ ์ง€์‹: Unit 9.2

ํ•ต์‹ฌ ๊ฐœ๋…

์–ด๋“œ๋ฐ”์ด์Šค์‹œ์ ์šฉ๋„
@Around๋ฉ”์„œ๋“œ ์ „ํ›„๊ฐ€์žฅ ๊ฐ•๋ ฅ, ๋ชจ๋“  ๊ฒƒ ๊ฐ€๋Šฅ
@Before๋ฉ”์„œ๋“œ ์‹คํ–‰ ์ „๋‹จ์ˆœ ์‚ฌ์ „ ์ž‘์—…
@AfterReturning์ •์ƒ ์™„๋ฃŒ ํ›„๊ฒฐ๊ณผ ์ฒ˜๋ฆฌ
@AfterThrowing์˜ˆ์™ธ ๋ฐœ์ƒ ์‹œ์˜ˆ์™ธ ๋กœ๊น…
@After์ •์ƒ/์˜ˆ์™ธ ๋ฌด๊ด€ (finally)์ž์› ํ•ด์ œ

์„ ํƒ ๊ฐ€์ด๋“œ:

  • ํŠธ๋žœ์žญ์…˜์ฒ˜๋Ÿผ ์ „ํ›„ + ์˜ˆ์™ธ ๋ชจ๋‘ ์ฒ˜๋ฆฌ ํ•„์š” โ†’ @Around
  • ๋‹จ์ˆœ ๋กœ๊น… (์ „ ๋˜๋Š” ํ›„) โ†’ @Before / @AfterReturning
  • ์ž์› ์ •๋ฆฌ โ†’ @After

@Around์˜ ๊ฐ•๋ ฅํ•จ:

  • proceed() ํ˜ธ์ถœ ์—ฌ๋ถ€๋ฅผ ๊ฒฐ์ • ๊ฐ€๋Šฅ โ†’ ํ˜ธ์ถœ ์ž์ฒด ์ฐจ๋‹จ
  • ๊ฒฐ๊ณผ/์˜ˆ์™ธ๋ฅผ ๋ณ€ํ™˜ ๊ฐ€๋Šฅ
  • ๋‹ค๋ฅธ ์–ด๋“œ๋ฐ”์ด์Šค๋กœ ๋ชป ํ•˜๋Š” ๊ฒƒ์ด ๊ฐ€๋Šฅ

์‹ค๋ฌด ๊ฒฐ๋ก :

"๊ณ ๋ฏผ๋˜๋ฉด @Around ์จ๋ผ. ๋‹ค๋ฅธ ๊ฑด ๋‹จ์ˆœ ์ผ€์ด์Šค์—์„œ๋งŒ"

์ž๊ธฐ ์ ๊ฒ€

  • @AfterThrowing์€ ์™œ ๊ฐ•๋ ฅํ•˜์ง€ ์•Š์€๊ฐ€? (ํžŒํŠธ: ์˜ˆ์™ธ๋ฅผ ๋ชป ๋ง‰์Œ)
  • @Around ๋ฉ”์„œ๋“œ๋Š” ์™œ ProceedingJoinPoint๋ฅผ ๋ฐ›๋Š”๊ฐ€? (ํžŒํŠธ: proceed ํ•„์š”)

๐Ÿ“š Phase 10 โ€” @Transactional์˜ ํ•จ์ •๊ณผ ํŠธ๋žœ์žญ์…˜ ์ „ํŒŒ (โ˜… 9์ฃผ์ฐจ ์ •์ )

๋ชฉํ‘œ: 7์ฃผ์ฐจ์—์„œ ๋‹ค๋ฃฌ @Transactional์˜ 5๊ฐ€์ง€ ํ•จ์ • ์ค‘ internal call ๋ฌธ์ œ ๋ฅผ ๊นŠ์ด ํŒŒ๊ณ , ํŠธ๋žœ์žญ์…˜ ์ „ํŒŒ์˜ 4๊ฐ€์ง€ ์‹œ๋‚˜๋ฆฌ์˜ค๋ฅผ ๋งˆ์Šคํ„ฐํ•œ๋‹ค.

Unit 10.1 โ€” @Transactional ๋™์ž‘ ์›๋ฆฌ ๋ณต์Šต

์„ ์ˆ˜ ์ง€์‹: 7์ฃผ์ฐจ Phase 7, Phase 6 (ProxyFactory)

ํ•ต์‹ฌ ์ •๋ฆฌ

@Transactional์€ ํŠธ๋žœ์žญ์…˜ AOP ๋‹ค.

๋™์ž‘ ํ๋ฆ„:
1. ๋นˆ ๋“ฑ๋ก ์‹œ ๋นˆ ํ›„์ฒ˜๋ฆฌ๊ธฐ๊ฐ€ ๊ฐ€๋กœ์ฑ”
2. @Transactional ๋ฉ”์„œ๋“œ๊ฐ€ ์žˆ์œผ๋ฉด โ†’ ํŠธ๋žœ์žญ์…˜ ํ”„๋ก์‹œ๋กœ ๊ต์ฒด
3. DI ์‹œ ์‹ค์ œ ๊ฐ์ฒด ๋Œ€์‹  ํ”„๋ก์‹œ ์ฃผ์ž…
4. ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ โ†’ ํ”„๋ก์‹œ๊ฐ€ ๊ฐ€๋กœ์ฑ„์„œ ํŠธ๋žœ์žญ์…˜ ์‹œ์ž‘/์ปค๋ฐ‹/๋กค๋ฐฑ

@Service
public class CallService {
    @Transactional
    public void internal() {
        // ํŠธ๋žœ์žญ์…˜ ์ ์šฉ๋จ
    }
}

// CallService ๋นˆ์€ ์‹ค์ œ๋กœ๋Š” ํ”„๋ก์‹œ ๊ฐ์ฒด

์ž๊ธฐ ์ ๊ฒ€

  • @Transactional์ด AOP์˜ ์–ด๋–ค ์–ด๋“œ๋ฐ”์ด์Šค์— ํ•ด๋‹นํ•˜๋Š”๊ฐ€? (ํžŒํŠธ: @Around)
  • 8์ฃผ์ฐจ Phase 6์˜ ์–ด๋–ค ๋ฉ”์ปค๋‹ˆ์ฆ˜์ด ์ ์šฉ๋œ ๊ฑด๊ฐ€? (ํžŒํŠธ: ProxyFactory + Advisor)

Unit 10.2 โ€” Internal call ๋ฌธ์ œ (โ˜…โ˜…โ˜… ๋ฉด์ ‘ ๋‹จ๊ณจ)

์„ ์ˆ˜ ์ง€์‹: Unit 10.1

ํ•ต์‹ฌ ์‹œ๋‚˜๋ฆฌ์˜ค

@Service
public class CallService {
    public void external() {
        log.info("call external");
        internal();  // โš ๏ธ ๊ฐ™์€ ํด๋ž˜์Šค์˜ ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ
    }
    
    @Transactional
    public void internal() {
        log.info("call internal");
    }
}

๋ฌธ์ œ:

  • callService.external() ํ˜ธ์ถœ
  • external()์€ @Transactional ์—†์Œ โ†’ ํ”„๋ก์‹œ๋Š” ๊ทธ๋Œ€๋กœ ํ†ต๊ณผ
  • external()์ด internal() ํ˜ธ์ถœ โ†’ ์‚ฌ์‹ค this.internal()
  • this๋Š” ํ”„๋ก์‹œ๊ฐ€ ์•„๋‹Œ target!
  • โ†’ internal()์˜ @Transactional์ด ๋ฌด์‹œ๋จ

๋ฌธ์ œ์˜ ๋ณธ์งˆ:

"ํ”„๋ก์‹œ๋Š” ์™ธ๋ถ€ ํ˜ธ์ถœ์„ ๊ฐ€๋กœ์ฑŒ ์ˆ˜ ์žˆ์ง€๋งŒ, ๋‚ด๋ถ€ ํ˜ธ์ถœ์€ ๊ฐ€๋กœ์ฑ„์ง€ ๋ชปํ•œ๋‹ค"

์›์ธ โ€” ์ž๋ฐ”์˜ ๋™์ž‘:

  • ๋ฉ”์„œ๋“œ ์•ž์— ์ฐธ์กฐ ์—†์œผ๋ฉด this
  • this๋Š” ์ž๊ธฐ ์ž์‹  ์ธ์Šคํ„ด์Šค
  • ํ”„๋ก์‹œ๋ฅผ ๊ฑฐ์น˜์ง€ ์•Š์Œ

์ž๊ธฐ ์ ๊ฒ€

  • this.internal()๊ณผ ๋‹ค๋ฅธ ๋นˆ์˜ internal() ํ˜ธ์ถœ์€ ๋™์ž‘์ด ๋‹ค๋ฅธ๊ฐ€? (ํžŒํŠธ: YES)
  • AspectJ ์ปดํŒŒ์ผ ์‹œ์  ๋ฐฉ์‹์ด๋ผ๋ฉด ์ด ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜๋Š”๊ฐ€? (ํžŒํŠธ: NO)

Unit 10.3 โ€” ํ•ด๊ฒฐ์ฑ… โ€” ํด๋ž˜์Šค ๋ถ„๋ฆฌ

์„ ์ˆ˜ ์ง€์‹: Unit 10.2

ํ•ต์‹ฌ ํ•ด๊ฒฐ

์›๋ฆฌ:

  • ๋‹ค๋ฅธ ํด๋ž˜์Šค์˜ ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ = ํ”„๋ก์‹œ๋ฅผ ๊ฑฐ์นจ
  • โ†’ @Transactional ๋ฉ”์„œ๋“œ๋ฅผ ๋ณ„๋„ ๋นˆ ์œผ๋กœ ๋ถ„๋ฆฌ
@Service
public class CallService {
    private final InternalService internalService;  // ๋‹ค๋ฅธ ๋นˆ ์ฃผ์ž…
    
    public void external() {
        log.info("call external");
        internalService.internal();  // โœ… ํ”„๋ก์‹œ ๊ฑฐ์นจ
    }
}

@Service
public class InternalService {
    @Transactional
    public void internal() {
        log.info("call internal");
    }
}

ํ˜ธ์ถœ ํ๋ฆ„:

test โ†’ CallService(์‹ค์ œ ๊ฐ์ฒด) โ†’ InternalService(ํ”„๋ก์‹œ) โ†’ InternalService(์‹ค์ œ) โ†’ DB
                                          โ†‘
                                    ์—ฌ๊ธฐ์„œ ํŠธ๋žœ์žญ์…˜ ์‹œ์ž‘

๋‹ค๋ฅธ ํ•ด๊ฒฐ์ฑ…๋“ค (์ฐธ๊ณ ):

  • AspectJ ์ปดํŒŒ์ผ ์‹œ์  ๋ฐฉ์‹ ์‚ฌ์šฉ
  • AopContext.currentProxy() ์‚ฌ์šฉ (๊ถŒ์žฅ X)

์ž๊ธฐ ์ ๊ฒ€

  • ์™œ ๊ฐ™์€ ํด๋ž˜์Šค์— ๋‘๋ฉด ์•ˆ ๋˜๋Š”๊ฐ€๋ฅผ ํ•œ ๋ฌธ์žฅ์œผ๋กœ?
  • ๊ฐ์ฒด์ง€ํ–ฅ ์„ค๊ณ„ ๊ด€์ ์—์„œ ๋ถ„๋ฆฌ๊ฐ€ ๋” ๋‚˜์€ ์ด์œ ๋Š”? (ํžŒํŠธ: SRP)

Unit 10.4 โ€” ํŠธ๋žœ์žญ์…˜ ์ „ํŒŒ๋ž€ + REQUIRED ๊ธฐ๋ณธ ๋™์ž‘

์„ ์ˆ˜ ์ง€์‹: Unit 10.3, 7์ฃผ์ฐจ Phase 7

ํ•ต์‹ฌ ๊ฐœ๋…

ํŠธ๋žœ์žญ์…˜ ์ „ํŒŒ(Propagation):

"์ด๋ฏธ ์ง„ํ–‰ ์ค‘์ธ ํŠธ๋žœ์žญ์…˜์ด ์žˆ์„ ๋•Œ, ์ƒˆ ํŠธ๋žœ์žญ์…˜ ์š”์ฒญ์„ ์–ด๋–ป๊ฒŒ ์ฒ˜๋ฆฌํ• ๊นŒ?"

REQUIRED (๊ธฐ๋ณธ ์˜ต์…˜):

  • ์ง„ํ–‰ ์ค‘์ธ ํŠธ๋žœ์žญ์…˜ ์žˆ์Œ โ†’ ์ฐธ์—ฌ
  • ์—†์Œ โ†’ ์ƒˆ ํŠธ๋žœ์žญ์…˜ ์‹œ์ž‘

์˜ˆ์‹œ โ€” ๋‘˜ ๋‹ค ์ปค๋ฐ‹:

@Test
void inner_commit() {
    log.info("์™ธ๋ถ€ ํŠธ๋žœ์žญ์…˜ ์‹œ์ž‘");
    TransactionStatus outer = txManager.getTransaction(new DefaultTransactionAttribute());
    log.info("outer.isNewTransaction()={}", outer.isNewTransaction());  // true
    
    log.info("๋‚ด๋ถ€ ํŠธ๋žœ์žญ์…˜ ์‹œ์ž‘");
    TransactionStatus inner = txManager.getTransaction(new DefaultTransactionAttribute());
    log.info("inner.isNewTransaction()={}", inner.isNewTransaction());  // false (์ฐธ์—ฌ)
    
    txManager.commit(inner);   // ์‹ค์ œ๋กœ๋Š” ์•ˆ ์ผ์–ด๋‚จ
    txManager.commit(outer);   // ์—ฌ๊ธฐ์„œ ์ง„์งœ commit
}

ํ•ต์‹ฌ ํ†ต์ฐฐ:

  • ์™ธ๋ถ€ + ๋‚ด๋ถ€ ํŠธ๋žœ์žญ์…˜์ด ํ•˜๋‚˜์˜ ๋ฌผ๋ฆฌ ํŠธ๋žœ์žญ์…˜ ์œผ๋กœ ๋ฌถ์ž„
  • ๋‚ด๋ถ€์˜ commit/rollback์€ "๋…ผ๋ฆฌ์ " ๋™์ž‘
  • ์‹ค์ œ ๋ฌผ๋ฆฌ commit/rollback์€ ์™ธ๋ถ€์—์„œ๋งŒ ๋ฐœ์ƒ

์ž๊ธฐ ์ ๊ฒ€

  • ๋…ผ๋ฆฌ ํŠธ๋žœ์žญ์…˜๊ณผ ๋ฌผ๋ฆฌ ํŠธ๋žœ์žญ์…˜์˜ ์ฐจ์ด๋ฅผ ์„ค๋ช…ํ•˜๋ผ
  • isNewTransaction()์ด true/false์ธ ์˜๋ฏธ๋Š”?

Unit 10.5 โ€” ๋‚ด๋ถ€ ๋กค๋ฐฑ์˜ ํ•จ์ • (UnexpectedRollbackException)

์„ ์ˆ˜ ์ง€์‹: Unit 10.4

ํ•ต์‹ฌ ์‹œ๋‚˜๋ฆฌ์˜ค

@Test
void inner_rollback() {
    TransactionStatus outer = txManager.getTransaction(...);
    TransactionStatus inner = txManager.getTransaction(...);
    
    txManager.rollback(inner);   // ๋‚ด๋ถ€ ๋กค๋ฐฑ
    
    assertThatThrownBy(() -> txManager.commit(outer))   // ์™ธ๋ถ€ ์ปค๋ฐ‹ ์‹œ๋„
        .isInstanceOf(UnexpectedRollbackException.class);  // โš ๏ธ ์˜ˆ์™ธ!
}

๋™์ž‘ ๋ถ„์„:

๋‚ด๋ถ€ ๋กค๋ฐฑ ์‹œ:
1. ์‹ ๊ทœ ํŠธ๋žœ์žญ์…˜์ด ์•„๋‹ˆ๋ฏ€๋กœ ์‹ค์ œ ๋กค๋ฐฑ ์•ˆ ํ•จ
2. ํŠธ๋žœ์žญ์…˜ ๋™๊ธฐํ™” ๋งค๋‹ˆ์ €์— rollbackOnly=true ํ‘œ์‹œ

์™ธ๋ถ€ ์ปค๋ฐ‹ ์‹œ:
1. ์‹ ๊ทœ ํŠธ๋žœ์žญ์…˜์ด๋ฏ€๋กœ ์‹ค์ œ ์ปค๋ฐ‹ ์‹œ๋„
2. rollbackOnly ํ‘œ์‹œ ๋ฐœ๊ฒฌ
3. ์ปค๋ฐ‹ ๋Œ€์‹  ๋กค๋ฐฑ ์‹คํ–‰
4. ๊ฐœ๋ฐœ์ž์—๊ฒŒ UnexpectedRollbackException ๋˜์ง

์ค‘์š”ํ•œ ํ†ต์ฐฐ โญ :

"๋‚ด๋ถ€๋“  ์™ธ๋ถ€๋“  ๋…ผ๋ฆฌ ํŠธ๋žœ์žญ์…˜์ด ํ•˜๋‚˜๋ผ๋„ ๋กค๋ฐฑ๋˜๋ฉด ๋ฌผ๋ฆฌ ํŠธ๋žœ์žญ์…˜์€ ๋กค๋ฐฑ"

์™œ ์˜ˆ์™ธ๋ฅผ ๋˜์ง€๋Š”๊ฐ€:

  • ๊ฐœ๋ฐœ์ž๋Š” commit์„ ํ˜ธ์ถœํ–ˆ์Œ
  • ์‹ค์ œ๋กœ๋Š” ๋กค๋ฐฑ๋จ
  • โ†’ ์‹œ์Šคํ…œ ์ผ๊ด€์„ฑ์„ ์œ„ํ•ด ๋ช…์‹œ์ ์œผ๋กœ ์•Œ๋ฆผ

์ž๊ธฐ ์ ๊ฒ€

  • "์กฐ์šฉํ•œ ๋กค๋ฐฑ"์ด ์ผ์–ด๋‚˜๋ฉด ์–ด๋–ค ์‚ฌ๊ณ ๊ฐ€ ๊ฐ€๋Šฅํ•œ๊ฐ€?
  • @Transactional์—์„œ ์ด ์˜ˆ์™ธ๊ฐ€ ์–ด๋–ป๊ฒŒ ๋…ธ์ถœ๋˜๋Š”๊ฐ€?

Unit 10.6 โ€” REQUIRES_NEW (๋ณ„๋„ ํŠธ๋žœ์žญ์…˜) + ์ „ํŒŒ ์˜ต์…˜

์„ ์ˆ˜ ์ง€์‹: Unit 10.5

ํ•ต์‹ฌ ๊ฐœ๋…

REQUIRES_NEW:

  • ํ•ญ์ƒ ์ƒˆ ํŠธ๋žœ์žญ์…˜ ์‹œ์ž‘
  • ์™ธ๋ถ€ ํŠธ๋žœ์žญ์…˜๊ณผ ์™„์ „ํžˆ ๋ถ„๋ฆฌ
  • ๊ฐ๊ฐ ๋ณ„๋„ commit/rollback

์˜ˆ์‹œ:

TransactionStatus outer = txManager.getTransaction(new DefaultTransactionAttribute());

DefaultTransactionAttribute def = new DefaultTransactionAttribute();
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
TransactionStatus inner = txManager.getTransaction(def);  // โญ ์ƒˆ ๋ฌผ๋ฆฌ ํŠธ๋žœ์žญ์…˜

txManager.rollback(inner);  // ๋‚ด๋ถ€๋งŒ ๋กค๋ฐฑ
txManager.commit(outer);    // ์™ธ๋ถ€๋Š” ์ •์ƒ ์ปค๋ฐ‹  โœ…

ํšจ๊ณผ:

  • ๋‚ด๋ถ€ ๋กค๋ฐฑ์ด ์™ธ๋ถ€์— ์˜ํ–ฅ X
  • ์™ธ๋ถ€ ๋กค๋ฐฑ์ด ๋‚ด๋ถ€์— ์˜ํ–ฅ X

โš ๏ธ ์ฃผ์˜์‚ฌํ•ญ:

  • ๋‚ด๋ถ€ ํŠธ๋žœ์žญ์…˜์ด ๋๋‚  ๋•Œ๊นŒ์ง€ ์™ธ๋ถ€ ์ปค๋„ฅ์…˜์€ ๋Œ€๊ธฐ ์ƒํƒœ
  • ๋™์‹œ์— 2๊ฐœ ์ปค๋„ฅ์…˜ ์‚ฌ์šฉ โ†’ ์ปค๋„ฅ์…˜ ํ’€ ๋น ๋ฅด๊ฒŒ ๊ณ ๊ฐˆ ๊ฐ€๋Šฅ

์ „ํŒŒ ์˜ต์…˜ 7๊ฐ€์ง€:

์˜ต์…˜์„ค๋ช…
REQUIRED๊ธฐ๋ณธ. ์žˆ์œผ๋ฉด ์ฐธ์—ฌ, ์—†์œผ๋ฉด ์‹œ์ž‘
REQUIRES_NEWํ•ญ์ƒ ์ƒˆ ํŠธ๋žœ์žญ์…˜
SUPPORT์žˆ์œผ๋ฉด ์ฐธ์—ฌ, ์—†์œผ๋ฉด ํŠธ๋žœ์žญ์…˜ ์—†์ด
NOT_SUPPORT์žˆ์œผ๋ฉด ๋ณด๋ฅ˜, ํŠธ๋žœ์žญ์…˜ ์—†์ด ์ง„ํ–‰
MANDATORY๋ฐ˜๋“œ์‹œ ์žˆ์–ด์•ผ ํ•จ, ์—†์œผ๋ฉด ์˜ˆ์™ธ
NEVERํŠธ๋žœ์žญ์…˜ ์žˆ์œผ๋ฉด ์˜ˆ์™ธ
NESTED์ค‘์ฒฉ ํŠธ๋žœ์žญ์…˜ (Savepoint)

์‹ค๋ฌด์—์„œ ๊ฐ€์žฅ ๋งŽ์ด ์“ฐ๋Š” ๊ฒƒ: REQUIRED, REQUIRES_NEW

์ž๊ธฐ ์ ๊ฒ€

  • REQUIRES_NEW๋ฅผ ๋‚จ๋ฐœํ•˜๋ฉด ์–ด๋–ค ์‚ฌ๊ณ ๊ฐ€? (ํžŒํŠธ: ์ปค๋„ฅ์…˜ ํ’€ ๊ณ ๊ฐˆ, ๋ฐ๋“œ๋ฝ)
  • ๋กœ๊น… ์ž‘์—…์—๋Š” ์–ด๋–ค ์ „ํŒŒ ์˜ต์…˜์ด ์ ํ•ฉํ• ๊นŒ? (ํžŒํŠธ: REQUIRES_NEW or SUPPORT)

๐ŸŽ“ ์ข…ํ•ฉ ์ž๊ธฐ ์ ๊ฒ€ (8-9์ฃผ์ฐจ ์กธ์—… ์‹œํ—˜)

Part A: 8์ฃผ์ฐจ

AOP ๋™๊ธฐ์™€ ํŒจํ„ด ์ง„ํ™”

  1. AOP์—์„œ ํ•ต์‹ฌ ๊ด€์ ๊ณผ ๋ถ€๊ฐ€ ๊ด€์ ์˜ ์ฐจ์ด๋Š”?
  2. "ํฉ์–ด์ง„ ๊ด€์‹ฌ์‚ฌ"์˜ ์ •์˜์™€ ์‚ฌ๋ก€ 3๊ฐ€์ง€๋Š”?
  3. ThreadLocal์˜ remove()๋ฅผ ๋ˆ„๋ฝํ•˜๋ฉด ์–ด๋–ค ์‚ฌ๊ณ ๊ฐ€ ๊ฐ€๋Šฅํ•œ๊ฐ€?
  4. ํ…œํ”Œ๋ฆฟ ๋ฉ”์„œ๋“œ ํŒจํ„ด์˜ ํ•œ๊ณ„ 2๊ฐ€์ง€๋Š”?
  5. ์ „๋žต ํŒจํ„ด์ด ์ƒ์† ๋Œ€์‹  ๋ฌด์—‡์„ ์‚ฌ์šฉํ•˜๋Š”๊ฐ€?
  6. ํ…œํ”Œ๋ฆฟ ์ฝœ๋ฐฑ ํŒจํ„ด์€ ์–ด๋–ค GOF ํŒจํ„ด์˜ ๋ณ€ํ˜•์ธ๊ฐ€?

ํ”„๋ก์‹œ

  1. ํ”„๋ก์‹œ์˜ ๋‘ ๊ฐ€์ง€ ์ฃผ์š” ๊ธฐ๋Šฅ์€?
  2. ํ”„๋ก์‹œ ํŒจํ„ด๊ณผ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ํŒจํ„ด์˜ ์ฐจ์ด๋ฅผ ์˜๋„๋กœ ์„ค๋ช…ํ•˜๋ผ
  3. JDK ๋™์  ํ”„๋ก์‹œ์˜ ์ „์ œ ์กฐ๊ฑด์€?
  4. CGLIB๊ฐ€ ์ธํ„ฐํŽ˜์ด์Šค ์—†์ด๋„ ์ž‘๋™ํ•˜๋Š” ์ด์œ ๋Š”?
  5. Spring Boot์˜ ๊ธฐ๋ณธ ํ”„๋ก์‹œ ๋ฐฉ์‹์€?

ProxyFactory์™€ ์ถ”์ƒํ™”

  1. Pointcut, Advice, Advisor์˜ ์ •์˜์™€ ๊ด€๊ณ„๋Š”?
  2. Advice ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๋„์ž…ํ•œ ์ด์œ ๋Š”?
  3. AspectJExpressionPointcut์ด ์‹ค๋ฌด ํ‘œ์ค€์ธ ์ด์œ ๋Š”?
  4. "ํ•˜๋‚˜์˜ target์— ์—ฌ๋Ÿฌ AOP ์ ์šฉ ์‹œ ํ”„๋ก์‹œ๋Š” ๋ช‡ ๊ฐœ?"

Part B: 9์ฃผ์ฐจ

์ž๋™ ํ”„๋ก์‹œ

  1. ๋นˆ ํ›„์ฒ˜๋ฆฌ๊ธฐ๊ฐ€ ๋ฌด์—‡์ธ๊ฐ€?
  2. AnnotationAwareAspectJAutoProxyCreator์˜ ์ด๋ฆ„์ด ์˜๋ฏธํ•˜๋Š” ๋ฐ”๋Š”?
  3. @Aspect๊ฐ€ ์ž๋™์œผ๋กœ ๋นˆ ๋“ฑ๋ก๋˜์ง€ ์•Š๋Š” ์ด์œ ๋Š”?

AOP ์šฉ์–ด

  1. ์กฐ์ธ ํฌ์ธํŠธ์™€ ํฌ์ธํŠธ์ปท์˜ ์ฐจ์ด๋Š”?
  2. ์œ„๋น™(Weaving)์ด๋ž€ ๋ฌด์—‡์ด๋ฉฐ Spring AOP์—์„œ ์–ธ์ œ ์ผ์–ด๋‚˜๋Š”๊ฐ€?
  3. AOP ์ ์šฉ 3๊ฐ€์ง€ ์‹œ์ ๊ณผ Spring AOP์˜ ์„ ํƒ์€?

Spring AOP ์‹ค์ „

  1. @Around๊ฐ€ ๊ฐ€์žฅ ๊ฐ•๋ ฅํ•œ ์ด์œ ๋Š”?
  2. ProceedingJoinPoint์™€ MethodInvocation์˜ ์ฐจ์ด๋Š”?
  3. @Pointcut์œผ๋กœ ๋ถ„๋ฆฌํ•˜๋Š” ์ด์œ  2๊ฐ€์ง€๋Š”?
  4. 5๊ฐ€์ง€ ์–ด๋“œ๋ฐ”์ด์Šค ์–ด๋…ธํ…Œ์ด์…˜๊ณผ ๊ฐ๊ฐ์˜ ์šฉ๋„๋Š”?

@Transactional ํ•จ์ •

  1. Internal call ๋ฌธ์ œ์˜ ๋ณธ์งˆ์„ ํ•œ ๋ฌธ์žฅ์œผ๋กœ?
  2. Internal call ๋ฌธ์ œ์˜ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์€?
  3. AspectJ ์ปดํŒŒ์ผ ๋ฐฉ์‹์€ internal call ๋ฌธ์ œ๊ฐ€ ์žˆ๋Š”๊ฐ€?

ํŠธ๋žœ์žญ์…˜ ์ „ํŒŒ

  1. ๋…ผ๋ฆฌ ํŠธ๋žœ์žญ์…˜๊ณผ ๋ฌผ๋ฆฌ ํŠธ๋žœ์žญ์…˜์˜ ์ฐจ์ด๋Š”?
  2. REQUIRED ์˜ต์…˜์˜ ๋™์ž‘ ๊ทœ์น™์€?
  3. ๋‚ด๋ถ€ ๋กค๋ฐฑ ์‹œ UnexpectedRollbackException์ด ๋˜์ ธ์ง€๋Š” ์ด์œ ๋Š”?
  4. REQUIRES_NEW์˜ ์ฃผ์˜์‚ฌํ•ญ์€?

๐Ÿ“Œ ํ•™์Šต ์šด์˜ ํŒ

9-์„น์…˜ ๋งˆ์Šคํ„ฐ ํ”„๋กฌํ”„ํŠธ๋กœ ๊นŠ์ด ํŒŒ์•ผ ํ•  Unit (ํŠน๋ณ„ํŒ)

์ด๋ฒˆ ์ฃผ์ฐจ๋Š” ๋ถ„๋Ÿ‰์ด ๋งŽ์€ ๋งŒํผ ๋ฐ˜๋“œ์‹œ ๊นŠ์ด ํŒŒ์•ผ ํ•  Unit ์„ ๋ช…ํ™•ํžˆ ํ‘œ์‹œ:

โ˜…โ˜…โ˜… ๋ฉด์ ‘ยท์‹ค๋ฌด ๋‹จ๊ณจ (๋ฐ˜๋“œ์‹œ):

  • Unit 5.2 โ€” JDK ๋™์  ํ”„๋ก์‹œ + InvocationHandler
  • Unit 6.1 โ€” ProxyFactory์˜ ์ž๋™ ์„ ํƒ
  • Unit 6.3 โ€” Pointcut + Advice = Advisor (3๋Œ€ ๊ฐœ๋…)
  • Unit 8.1 โ€” @Aspect + @Around
  • Unit 8.4 โ€” AOP ์šฉ์–ด 7๊ฐ€์ง€
  • Unit 10.2 โ€” Internal call ๋ฌธ์ œ
  • Unit 10.5 โ€” UnexpectedRollbackException

โ˜…โ˜… ๋งค์šฐ ๊ถŒ์žฅ:

  • Unit 1.3 โ€” ThreadLocal๊ณผ remove()
  • Unit 4.3 โ€” ํ”„๋ก์‹œ vs ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ ์˜๋„ ๊ตฌ๋ถ„
  • Unit 5.3 โ€” CGLIB
  • Unit 9.3 โ€” ์–ด๋“œ๋ฐ”์ด์Šค 5์ข…
  • Unit 10.6 โ€” REQUIRES_NEW

Phase๋ณ„ ์ง„๋„ ์ฒดํฌ๋ฆฌ์ŠคํŠธ

[ Part A โ€” 8์ฃผ์ฐจ ]
[ ] Phase 1 โ€” AOP ์ž…๋ฌธ๊ณผ ๋™๊ธฐ (Unit 1.1~1.3)
[ ] Phase 2 โ€” ๋””์ž์ธ ํŒจํ„ด์˜ ์ง„ํ™” (Unit 2.1~2.4)
[ ] Phase 3 โ€” ์ฝœ๋ฐฑ๊ณผ ํ”„๋ก์‹œ์˜ ๋งŒ๋‚จ (Unit 3.1~3.3)
[ ] Phase 4 โ€” ํ”„๋ก์‹œ vs ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ (Unit 4.1~4.3)
[ ] Phase 5 โ€” ๋™์  ํ”„๋ก์‹œ ๊ธฐ์ˆ  (Unit 5.1~5.3)
[ ] Phase 6 โ€” ProxyFactory ํ†ตํ•ฉ ์ถ”์ƒํ™” (Unit 6.1~6.4)  โ˜… 8์ฃผ์ฐจ ์ •์ 

[ Part B โ€” 9์ฃผ์ฐจ ]
[ ] Phase 7 โ€” ๋นˆ ํ›„์ฒ˜๋ฆฌ๊ธฐ์™€ ์ž๋™ ํ”„๋ก์‹œ (Unit 7.1~7.3)
[ ] Phase 8 โ€” @Aspect์™€ AOP ์šฉ์–ด (Unit 8.1~8.4)
[ ] Phase 9 โ€” Spring AOP ์‹ค์ „ ํŒจํ„ด (Unit 9.1~9.3)
[ ] Phase 10 โ€” @Transactional + ํŠธ๋žœ์žญ์…˜ ์ „ํŒŒ (Unit 10.1~10.6)  โ˜… 9์ฃผ์ฐจ ์ •์ 

[ ] ์ข…ํ•ฉ ์ž๊ธฐ ์ ๊ฒ€ 32๋ฌธํ•ญ ํ†ต๊ณผ

8-9์ฃผ์ฐจ์˜ ๋‘ ์ •์ 

8์ฃผ์ฐจ ์ •์  โ€” Phase 6 (ProxyFactory):

  • ๋ชจ๋“  ๋””์ž์ธ ํŒจํ„ด ํ•™์Šต์ด ํ•œ ๊ณณ์œผ๋กœ ๋ชจ์ด๋Š” ์ง€์ 
  • 5์ฃผ์ฐจ OOP ์›์น™ + 8์ฃผ์ฐจ ํŒจํ„ด ์ง„ํ™” + Spring ํ†ตํ•ฉ

9์ฃผ์ฐจ ์ •์  โ€” Phase 10 (ํŠธ๋žœ์žญ์…˜ ์ „ํŒŒ):

  • AOP ํ•™์Šต์˜ ๊ฒฐ์‹ค
  • 7์ฃผ์ฐจ @Transactional์ด ์™œ ๊ทธ๋ ‡๊ฒŒ ๋™์ž‘ํ–ˆ๋Š”์ง€ ์™„์ „ ์ดํ•ด
  • ๋ฉด์ ‘ยท์‹ค๋ฌด ๋ชจ๋‘์—์„œ ๊ฐ€์žฅ ์ž์ฃผ ๋ถ€๋”ชํžˆ๋Š” ์˜์—ญ

1~9์ฃผ์ฐจ ํ†ตํ•ฉ ํ๋ฆ„์˜ ์ ˆ์ •

8-9์ฃผ์ฐจ๋Š” 1~7์ฃผ์ฐจ์˜ ํ•™์Šต์ด ๋ชจ๋‘ ๊ฒฐํ•ฉ ๋˜๋Š” ์ง€์ :

์ถœ์ฒ˜ ์ฃผ์ฐจ8-9์ฃผ์ฐจ์—์„œ์˜ ์—ญํ• 
1์ฃผ์ฐจ (OOP, ์ธํ„ฐํŽ˜์ด์Šค)ํ”„๋ก์‹œยท์ „๋žต ํŒจํ„ด์˜ ๊ธฐ๋ฐ˜
3์ฃผ์ฐจ (๋žŒ๋‹ค, ํ•จ์ˆ˜ํ˜•)Advice/Callback์˜ ๋žŒ๋‹ค ํ™œ์šฉ
4์ฃผ์ฐจ (๋ฉ€ํ‹ฐ์Šค๋ ˆ๋“œ, ThreadLocal)๋กœ๊ทธ ์ถ”์ ๊ธฐ์˜ ๋™์‹œ์„ฑ ํ•ด๊ฒฐ
5์ฃผ์ฐจ (๋””์ž์ธ ํŒจํ„ด, OCP)ํ…œํ”Œ๋ฆฟ ๋ฉ”์„œ๋“œ โ†’ ์ „๋žต ํŒจํ„ด ์ง„ํ™”
5์ฃผ์ฐจ (์‹ฑ๊ธ€ํ†ค ๋นˆ)์ž๋™ ํ”„๋ก์‹œ์˜ ๋นˆ ๊ต์ฒด ๋ฉ”์ปค๋‹ˆ์ฆ˜
6์ฃผ์ฐจ (JdbcTemplate)ํ…œํ”Œ๋ฆฟ ์ฝœ๋ฐฑ ํŒจํ„ด์˜ ์‹ค์ œ ์‚ฌ๋ก€
7์ฃผ์ฐจ (@Transactional)8-9์ฃผ์ฐจ ํ•™์Šต์˜ ๋™๊ธฐ + ์ ์šฉ ์‚ฌ๋ก€

โ†’ 8-9์ฃผ์ฐจ๋Š” ์ž๋ฐ”ยทSpring ํ•™์Šต์˜ ํด๋ผ์ด๋งฅ์Šค

profile
Software Developer

0๊ฐœ์˜ ๋Œ“๊ธ€