โญ Spring AOP, ๐Ÿค” Proxy๋กœ ์ •๋ฆฌํ•ด๋ณด์ž!

devdoยท2021๋…„ 12์›” 30์ผ
0

Spring

๋ชฉ๋ก ๋ณด๊ธฐ
9/11
post-thumbnail

AOP(Aspect Oriented Programming)

: ๊ด€์  ์ง€ํ–ฅ ํ”„๋กœ๊ทธ๋ž˜๋ฐ

์Šคํ”„๋ง ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์€ ๋Œ€๋ถ€๋ถ„ ํŠน๋ณ„ํ•œ ๊ฒฝ์šฐ๋ฅผ ์ œ์™ธํ•˜๊ณ ๋Š” MVC ์›น ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ๋Š” Web Layer, Business Layer, Data Layer ๋กœ ์ •์˜.

  • Application Layer : REST API๋ฅผ ์ œ๊ณตํ•˜๋ฉฐ, Client ์ค‘์‹ฌ์˜ ๋กœ์ง ์ ์šฉ
  • Business Layer : ๋‚ด๋ถ€ ์ •์ฑ…์— ๋”ฐ๋ฅธ logic๋ฅผ ๊ฐœ๋ฐœํ•˜๋ฉฐ, ์ฃผ๋กœ ํ•ด๋‹น ๋ถ€๋ถ„์„ ๊ฐœ๋ฐœ
  • Data Layer : ๋ฐ์ดํ„ฐ ๋ฒ ์ด์Šค ๋ฐ ์™ธ๋ถ€์™€์˜ ์—ฐ๋™์„ ์ฒ˜๋ฆฌ

์Šคํ”„๋ง DI๊ฐ€ ์˜์กด์„ฑ(new) ์ฃผ์ž…์ด๋ผ๋ฉด,

โญ ์Šคํ”„๋ง AOP๋Š” ๋กœ์ง(code) ์ฃผ์ž…์ด๋ผ๊ณ  ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

๋กœ๊น…, ๋ณด์•ˆ, ํŠธ๋žœ์žญ์…˜, validation ๋“ฑ๋“ฑ ๊ณตํ†ต๋œ ๊ธฐ๋Šฅ์„ ๋ชจ์•„๋†“์•„ ๋ฐ˜๋ณต์ ์œผ๋กœ ๋‚˜ํƒ€๋‚˜๋Š” ๋ถ€๋ถ„์ด ์žˆ๋Š”๋ฐ ์ด๋ฅผ ํšก๋‹จ๊ด€์‹ฌ(cross-cutting concern)์ด๋ผ๊ณ  ํ•œ๋‹ค.

โœจ AOP๋Š” ํ•ต์‹ฌ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์— ์˜ํ–ฅ์„ ๋ฐ›๊ฒŒ ํ•˜์ง€ ์•Š๊ณ  ๋ฐ˜๋ณต์ ์ธ ๊ณตํ†ต ๋ถ€๋ถ„์„ ๋ชจ๋“ˆํ™”ํ•ด ๋ชฐ์•„์ฃผ๋Š” ๊ธฐ์ˆ ์ด๋‹ค.


IoC ์ปจํ…Œ์ด๋„ˆ์™€ AOP Proxy

Spring์—๋Š” ํฌ๊ฒŒ 2๊ฐ€์ง€ ํ”„๋ก์‹œ ๊ตฌํ˜„์ฒด๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค. JDK PROXY(=Dynamic PROXY) ์™€ CGLib์ด๋‹ค. Spring AOP๋Š” PROXY์˜ ๋งค์ปค๋‹ˆ์ฆ˜์„ ๊ธฐ๋ฐ˜์œผ๋กœ AOP PROXY๋ฅผ ์ œ๊ณตํ•˜๊ณ  ์žˆ๋‹ค.

์œ„ ๊ทธ๋ฆผ์ฒ˜๋Ÿผ Spring AOP๋Š” ์‚ฌ์šฉ์ž์˜ ํŠน์ • ํ˜ธ์ถœ ์‹œ์ ์— IoC ์ปจํ…Œ์ด๋„ˆ์— ์˜ํ•ด AOP๋ฅผ ํ•  ์ˆ˜ ์žˆ๋Š” Proxy Bean์„ ์ƒ์„ฑํ•ด์ค€๋‹ค.

๋™์ ์œผ๋กœ ์ƒ์„ฑ๋œ Proxy Bean์€ ํƒ€๊นƒ์˜ ๋ฉ”์„œ๋“œ๊ฐ€ ํ˜ธ์ถœ๋˜๋Š” ์‹œ์ ์— ๋ถ€๊ฐ€๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•  ๋ฉ”์„œ๋“œ๋ฅผ ์ž์ฒด์ ์œผ๋กœ ํŒ๋‹จํ•ด ๊ฐ€๋กœ์ฑ„์–ด ๋ถ€๊ฐ€๊ธฐ๋Šฅ์„ ์ฃผ์ž…ํ•œ๋‹ค. ์ด๋ฅผ ํ˜ธ์ถœ์‹œ์ ์— ๋™์ ์œผ๋กœ ์œ„๋น™์„ ํ•œ๋‹คํ•ด ๋Ÿฐํƒ€์ž„ ์œ„๋น™(Runtime Weaving)์ด๋ผ๊ณ  ํ•œ๋‹ค.

Spring AOP๋Š” ๋Ÿฐํƒ€์ž„ ์œ„๋น™ ๋ฐฉ์‹์„ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•˜๊ณ  ์žˆ๊ณ , Spring ์—์„œ๋Š” ์ƒํ™ฉ์— ๋”ฐ๋ผ JDK Proxy์™€ CGLib๋ฐฉ์‹์„ ํ†ตํ•ด Proxy Bean์„ ์ƒ์„ฑํ•ด์ค€๋‹ค.


ํ”„๋ก์‹œ๋ž€?

JDK PROXY์™€ CGLib๋ฅผ ์„ ํƒํ•˜๋Š” ๊ธฐ์ค€

ํ”„๋ก์‹œ์˜ ์‚ฌ์ „์  ์ •์˜๋Š” '๋Œ€๋ฆฌ์ธ'์œผ๋กœ, ๊ฐ„๋‹จํ•˜๊ฒŒ ์„ค๋ช…ํ•˜๋ฉด ๋‚ด๊ฐ€ ์–ด๋–ค ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๊ณ  ํ•  ๋•Œ ํ•ด๋‹น ๊ฐ์ฒด์— ์ง์ ‘ ์š”์ฒญํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹Œ ์ค‘๊ฐ„์— ๊ฐ€์งœ ํ”„๋ก์‹œ ๊ฐ์ฒด(๋Œ€๋ฆฌ์ธ)๋ฅผ ๋‘์–ด์„œ ํ”„๋ก์‹œ ๊ฐ์ฒด๊ฐ€ ๋Œ€์‹ ํ•ด์„œ ์š”์ฒญ์„ ๋ฐ›์•„ ์‹ค์ œ ๊ฐ์ฒด๋ฅผ ํ˜ธ์ถœํ•ด ์ฃผ๋„๋ก ํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

์Šคํ”„๋ง์—์„œ ์‚ฌ์šฉ๋˜๋Š” ํ”„๋ก์‹œ ๊ธฐ์ˆ ์€ ํฌ๊ฒŒ ๋‘ ๊ฐ€์ง€๋กœ ๋‚˜๋ˆŒ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


1) JDK ๋™์  ํ”„๋ก์‹œ

JDK ๋™์  ํ”„๋ก์‹œ๋Š” ์ž๋ฐ”์—์„œ ์ œ๊ณตํ•˜๋Š” ๊ธฐ๋ณธ์ ์ธ ํ”„๋ก์‹œ ๊ธฐ์ˆ ์ž…๋‹ˆ๋‹ค.
์ž๋ฐ”์˜ โญ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ๋™์ž‘ํ•˜๋ฉฐ, ์ธํ„ฐํŽ˜์ด์Šค์˜ ๊ตฌํ˜„ ํด๋ž˜์Šค๋ฅผ ์ž๋™์œผ๋กœ ์ƒ์„ฑํ•˜์—ฌ ํ”„๋ก์‹œ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. ์ธํ„ฐํŽ˜์ด์Šค์˜ ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด ํ”„๋ก์‹œ ๊ฐ์ฒด๋Š” InvocationHandler๋ฅผ ํ†ตํ•ด ํ•ด๋‹น ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๊ณ  ๋ถ€๊ฐ€ ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.

JDK ๋™์  ํ”„๋ก์‹œ ๊ธฐ์ˆ ์„ ์‚ฌ์šฉํ•˜๋ฉด ๊ฐœ๋ฐœ์ž๊ฐ€ ์ง์ ‘ ํ”„๋ก์‹œ ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค์ง€ ์•Š์•„๋„ ๋œ๋‹ค. ์ด๋ฆ„ ๊ทธ๋Œ€๋กœ ํ”„๋ก์‹œ ๊ฐ์ฒด๋ฅผ ๋™์ ์œผ๋กœ ๋Ÿฐํƒ€์ž„์— ๊ฐœ๋ฐœ์ž ๋Œ€์‹  ๋งŒ๋“ค์–ด์ค€๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๋™์  ํ”„๋ก์‹œ์— ์›ํ•˜๋Š” ์‹คํ–‰ ๋กœ์ง์„ ์ง€์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.

JDK ๋™์  ํ”„๋ก์‹œ ๊ธฐ์ˆ  ๋•๋ถ„์— ์ ์šฉ ๋Œ€์ƒ ๋งŒํผ ํ”„๋ก์‹œ ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค์ง€ ์•Š์•„๋„ ๋œ๋‹ค.

๊ฒฐ๊ณผ์ ์œผ๋กœ ํ”„๋ก์‹œ ํด๋ž˜์Šค๋ฅผ ์ˆ˜ ์—†์ด ๋งŒ๋“ค์–ด์•ผ ํ•˜๋Š” ๋ฌธ์ œ๋„ ํ•ด๊ฒฐํ•˜๊ณ , ๋ถ€๊ฐ€ ๊ธฐ๋Šฅ ๋กœ์ง๋„ ํ•˜๋‚˜์˜ ํด๋ž˜์Šค์— ๋ชจ์•„์„œ ๋‹จ์ผ ์ฑ…์ž„ ์›์น™(SRP)๋„ ์ง€ํ‚ฌ ์ˆ˜ ์žˆ๊ฒŒ ๋˜์—ˆ๋‹ค.

์ ์šฉํ›„!

โญ JDK ๋™์  ํ”„๋ก์‹œ - ํ•œ๊ณ„

* JDK ๋™์  ํ”„๋ก์‹œ๋Š” ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ํ•„์ˆ˜์ด๋‹ค.

JDK ๋™์  ํ”„๋ก์‹œ๋Š” ์ž๋ฐ”์˜ ๋ฆฌํ”Œ๋ ‰์…˜ ๊ธฐ์ˆ ์„ ์‚ฌ์šฉํ•œ๋‹ค! ์ž, ๊ทธ๋Ÿฌ๋ฉด ๋ฆฌํ”Œ๋ ˆ์…˜ ๊ธฐ์ˆ ์„ ์•Œ์•„๋ณด์ž!

๋ฆฌํ”Œ๋ ‰์…˜์€ ๋Ÿฐํƒ€์ž„์— ๋ฉ”์„œ๋“œ๋‚˜ ํ•„๋“œ๋ฅผ ์ฐพ์•„์„œ ํ˜ธ์ถœํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ •์  ํ˜ธ์ถœ๋ณด๋‹ค ํ›จ์”ฌ ๋А๋ฆฌ๊ณ  CPU ์ž์›์„ ๋” ๋งŽ์ด ์†Œ๋ชจํ•œ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด, ํ•œ ๊ฐœ๋ฐœ์ž๊ฐ€ ์ง์ ‘ ํ…Œ์ŠคํŠธํ•œ ๊ฒฐ๊ณผ์— ๋”ฐ๋ฅด๋ฉด, ๋™์ผํ•œ ๊ฐ์ฒด๋ฅผ 8์ฒœ๋งŒ ๋ฒˆ ์ƒ์„ฑํ•˜๊ณ  ํ•„๋“œ๋ฅผ ์„ค์ •ํ•˜๋Š” ์ž‘์—…์—์„œ:

- ๋ฆฌํ”Œ๋ ‰์…˜ ์‚ฌ์šฉ: ์•ฝ 42์ดˆ, CPU ์‚ฌ์šฉ๋ฅ  44%
์ฆ‰, ์•ฝ 8~10๋ฐฐ ๋А๋ฆฌ๊ณ  CPU ๋ถ€ํ•˜๋„ ํ›จ์”ฌ ํผ.

JDK ๋™์  ํ”„๋ก์‹œ๋Š” ๋‚ด๋ถ€์ ์œผ๋กœ java.lang.reflect.Proxy๋ฅผ ์‚ฌ์šฉํ•ด์„œ ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•  ๋•Œ๋งˆ๋‹ค InvocationHandler.invoke()๋ฅผ ํ†ตํ•ด ๋ฆฌํ”Œ๋ ‰์…˜์œผ๋กœ ๋ฉ”์„œ๋“œ๋ฅผ ์ฐพ์•„ ์‹คํ–‰ํ•ด. ์ด ๊ณผ์ •์ด ๋ฐ˜๋ณต๋˜๋ฉด ์„ฑ๋Šฅ ์ €ํ•˜๊ฐ€ ๋ˆ„์ ๋˜๊ธฐ ๋•Œ๋ฌธ์—, ์Šคํ”„๋ง์—์„œ๋Š” CGLIB์ฒ˜๋Ÿผ ๋ฐ”์ดํŠธ์ฝ”๋“œ๋ฅผ ์ง์ ‘ ์กฐ์ž‘ํ•ด์„œ ์ •์  ํ˜ธ์ถœ์— ๊ฐ€๊นŒ์šด ๋ฐฉ์‹์„ ์„ ํ˜ธํ•˜๊ฒŒ ๋œ ๊ฑฐ์•ผ.

์ด๋Ÿฐ ์ด์œ ๋กœ, ์Šคํ”„๋ง ๋ถ€ํŠธ๋Š” ์ธํ„ฐํŽ˜์ด์Šค ์œ ๋ฌด์™€ ์ƒ๊ด€์—†์ด ๋” ๋น ๋ฅด๊ณ  ์œ ์—ฐํ•œ CGLIB๋ฅผ ๊ธฐ๋ณธ๊ฐ’์œผ๋กœ ์ฑ„ํƒํ•œ ๊ฒƒ์ด๋‹ค!

์ฐธ๊ณ ๋กœ ์šฐ๋ฆฌ๊ฐ€ CGLIB๋ฅผ ์ง์ ‘ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ๋Š” ๊ฑฐ์˜ ์—†๋‹ค. ์ดํ›„์— ์„ค๋ช…ํ•  ์Šคํ”„๋ง์˜ ProxyFactory ๋ผ๋Š” ๊ฒƒ์ด ์ด ๊ธฐ์ˆ ์„ ํŽธ๋ฆฌํ•˜๊ฒŒ ์‚ฌ์šฉํ•˜๊ฒŒ ๋„์™€์ฃผ๊ธฐ ๋•Œ๋ฌธ์—, ๋„ˆ๋ฌด ๊นŠ์ด์žˆ๊ฒŒ ํŒŒ๊ธฐ ๋ณด๋‹ค๋Š” CGLIB๊ฐ€ ๋ฌด์—‡์ธ์ง€ ๋Œ€๋žต ๊ฐœ๋…๋งŒ ์žก์œผ๋ฉด ๋œ๋‹ค.

๐Ÿ“Œ jdk ๋™์  ํ”„๋ก์‹œ vs CGLIB ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ํ…Œ์ŠคํŠธ

https://velog.io/@jaeyeon93/๋ฆฌํ”Œ๋ ‰์…˜์€-์–ผ๋งˆ๋‚˜-๋А๋ฆด๊นŒ


2) CGLIB Proxy

CGLIB (Code Generation Library) Proxy๋Š” JDK Dynamic Proxy์™€ ๋‹ฌ๋ฆฌ ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ์•„๋‹Œ ํด๋ž˜์Šค๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค.

๋Ÿฐํƒ€์ž„์— ํด๋ž˜์Šค์˜ ์„œ๋ธŒํด๋ž˜์Šค๋ฅผ ์ƒ์„ฑํ•˜์—ฌ ํ”„๋ก์‹œ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ’ฅ ๋‹จ, ์ƒ์†์ด ๋ถˆ๊ฐ€๋Šฅํ•œ final ํด๋ž˜์Šค๋‚˜ private ์ƒ์„ฑ์ž๋ฅผ ๊ฐ€์ง„ ํด๋ž˜์Šค๋Š” ํ”„๋ก์‹œ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

๋ฉ”์†Œ๋“œ ํ˜ธ์ถœ ์‹œ ํ”„๋ก์‹œ ๊ฐ์ฒด๋Š” MethodInterceptor๋ฅผ ํ†ตํ•ด ํ•ด๋‹น ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๊ณ  ๋ถ€๊ฐ€ ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.


CGLIB๋ž€?

CGLIB ๋ผ๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋กœ ๋‚ด ํด๋ž˜์Šค๋ฅผ ์ƒ์† ๋ฐ›์€ ๊ฐ€์งœ ํ”„๋ก์‹œ ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค์–ด์„œ ์ฃผ์ž…ํ•œ๋‹ค.

  • CGLIB๋Š” ๋ฐ”์ดํŠธ์ฝ”๋“œ๋ฅผ ์กฐ์ž‘ํ•ด์„œ ๋™์ ์œผ๋กœ ํด๋ž˜์Šค๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๊ธฐ์ˆ ์„ ์ œ๊ณตํ•˜๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ด๋‹ค.
  • CGLIB๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ์—†์–ด๋„ ๊ตฌ์ฒด ํด๋ž˜์Šค๋งŒ ๊ฐ€์ง€๊ณ  ๋™์  ํ”„๋ก์‹œ๋ฅผ ๋งŒ๋“ค์–ด๋‚ผ ์ˆ˜ ์žˆ๋‹ค.
  • CGLIB๊ฐ€ ๋™์ ์œผ๋กœ ์ƒ์„ฑํ•˜๋Š” ํด๋ž˜์Šค ์ด๋ฆ„์€ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ทœ์น™์œผ๋กœ ์ƒ์„ฑ๋œ๋‹ค.
    ๋Œ€์ƒํด๋ž˜์Šค$$EnhancerByCGLIB$$์ž„์˜์ฝ”๋“œ
    ์ฐธ๊ณ ๋กœ ๋‹ค์Œ์€ JDK Proxy๊ฐ€ ์ƒ์„ฑํ•œ ํด๋ž˜์Šค ์ด๋ฆ„์ด๋‹ค.
    proxyClass=class com.sun.proxy.$Proxy1

์ด ๊ฐ€์งœ ํ”„๋ก์‹œ ๊ฐ์ฒด๋Š” ์‹ค์ œ ์š”์ฒญ์ด ์˜ค๋ฉด ๊ทธ๋•Œ ๋‚ด๋ถ€์—์„œ ์‹ค์ œ ๋นˆ์„ ์š”์ฒญํ•˜๋Š” ์œ„์ž„ ๋กœ์ง์ด ๋“ค์–ด์žˆ๋‹ค.

๊ฐ€์งœ ํ”„๋ก์‹œ ๊ฐ์ฒด๋Š” ์‹ค์ œ request scope ์™€๋Š” ๊ด€๊ณ„๊ฐ€ ์—†๋‹ค. ๊ทธ๋ƒฅ ๊ฐ€์งœ์ด๊ณ , ๋‚ด๋ถ€์— ๋‹จ์ˆœํ•œ ์œ„์ž„ ๋กœ์ง๋งŒ ์žˆ๊ณ , ์‹ฑ๊ธ€ํ†ค์ฒ˜๋Ÿผ ๋™์ž‘ํ•œ๋‹ค.


request scope ํ”„๋ก์‹œ ๋™์ž‘

์Šคํ”„๋ง์—์„œ๋Š” ํ”„๋ก์‹œ ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด ๋นˆ์œผ๋กœ ํ”„๋ก์‹œ๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค.

โญ ๊ทธ ํ”„๋ก์‹œ๋ฅผ request scope ํ”„๋ก์‹œ๋ผ๊ณ  ํ•œ๋‹ค.

request scope ํ”„๋ก์‹œ๋ž€, HTTP ์š”์ฒญ ๋‹จ์œ„์˜ ์Šค์ฝ”ํ”„๋ฅผ ๊ฐ€์ง€๋Š” ๋นˆ(Bean)์— ๋Œ€ํ•œ ํ”„๋ก์‹œ ๊ฐ์ฒด๋ฅผ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.

์ด๋Ÿฌํ•œ ํ”„๋ก์‹œ ๊ฐ์ฒด๋Š” ์‹ค์ œ ๋นˆ์ด ์ฒ˜์Œ ์š”์ฒญ๋  ๋•Œ ์ƒ์„ฑ๋˜๋ฉฐ, ๊ทธ ํ›„์—๋Š” ์š”์ฒญ์— ๋Œ€ํ•œ ๋ชจ๋“  ๋นˆ์˜ ์ฐธ์กฐ๊ฐ€ ์ด ํ”„๋ก์‹œ ๊ฐ์ฒด๋กœ ์ „๋‹ฌ๋œ๋‹ค.

์ด ํ”„๋ก์‹œ ๊ฐ์ฒด๋Š” ํ•ด๋‹น ์š”์ฒญ ๋ฒ”์œ„ ๋‚ด์—์„œ ๋นˆ์˜ ์ƒ๋ช…์ฃผ๊ธฐ๋ฅผ ๊ด€๋ฆฌํ•˜๊ณ , ๋นˆ์ด ์Šค์ฝ”ํ”„์—์„œ ์ œ๊ฑฐ๋  ๋•Œ ํ•ด๋‹น ๋นˆ์˜ destroy() ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ๋นˆ์ด ์ œ๋Œ€๋กœ ์ข…๋ฃŒ๋˜๋„๋ก ๋ณด์žฅํ•œ๋‹ค.

์ด๋ฅผ ํ†ตํ•ด, Spring ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ Request scope ๋นˆ์„ ์‰ฝ๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ๋นˆ์ด ์š”์ฒญ ๋ฒ”์œ„ ๋‚ด์—์„œ๋งŒ ์กด์žฌํ•˜๊ณ  ๋‹ค๋ฅธ ์š”์ฒญ์—์„œ๋Š” ์žฌ์‚ฌ์šฉ๋˜์ง€ ์•Š๋„๋ก ํ•  ์ˆ˜ ์žˆ๋‹ค.

  • ProxyMode๋ฅผ ์„ค์ •ํ•˜๊ฒŒ ๋˜๋ฉด, ์˜์กด์„ฑ ์ฃผ์ž…์„ ํ†ตํ•ด ์ฃผ์ž…๋˜๋Š” ๋นˆ์€ ์‹ค์ œ ๋นˆ์ด ์•„๋‹Œ ํ•ด๋‹น ๋นˆ์„ ์ƒ์†๋ฐ›์€ ๊ฐ€์งœ ํ”„๋ก์‹œ ๊ฐ์ฒด์ด๋‹ค.
  • ์Šคํ”„๋ง์€ CGLIB์ด๋ผ๋Š” ๋ฐ”์ดํŠธ ์ฝ”๋“œ๋ฅผ ์กฐ์ž‘ํ•˜๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•ด์„œ ํ”„๋ก์‹œ ๊ฐ์ฒด๋ฅผ ์ฃผ์ž…ํ•ด์ค€๋‹ค.
  • ํ”„๋ก์‹œ ๊ฐ์ฒด ๋‚ด๋ถ€์—๋Š” ์‹ค์ œ ๋นˆ์„ ์š”์ฒญํ•˜๋Š” ๋กœ์ง์ด ๋“ค์–ด์žˆ์–ด, ํด๋ผ์ด์–ธํŠธ์˜ ์š”์ฒญ์ด ์˜ค๋ฉด ๊ทธ๋•Œ ์‹ค์ œ ๋นˆ์„ ํ˜ธ์ถœํ•ด์ค€๋‹ค.(์‹ค์ œ ๋นˆ์˜ ์กฐํšŒ๋ฅผ ํ•„์š”ํ•œ ์‹œ์ ๊นŒ์ง€ ์ง€์—ฐ ์ฒ˜๋ฆฌ)
  • ํ”„๋ก์‹œ ๊ฐ์ฒด๋Š” ์›๋ž˜ ๋นˆ์„ ์ƒ์†๋ฐ›์•„์„œ ๋งŒ๋“ค์–ด์ง€๊ธฐ ๋•Œ๋ฌธ์— ํด๋ผ์ด์–ธํŠธ ์ž…์žฅ์—์„œ๋Š” ์‹ค์ œ ๋นˆ์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ๊ณผ ๋˜‘๊ฐ™์€ ๋ฐฉ๋ฒ•์œผ๋กœ ์‚ฌ์šฉํ•˜๋ฉด ๋œ๋‹ค.
  • @Scope ์• ๋…ธํ…Œ์ด์…˜์˜ proxyMode ์˜ต์…˜์„ ์‚ฌ์šฉํ•˜์—ฌ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.
@Component //ํด๋ž˜์Šค๊ฐ€ ์•„๋‹Œ ์ธํ„ฐํŽ˜์ด์Šค๋ผ๋ฉด ScopedProxyMode.INTERFACE 
@Scope(proxyMode = ScopedProxyMode.TARGET_CLASS) //ํ”„๋ก์‹œ ์„ค์ • 
public class HelloBean { 
	public void hello() { ... } 
} 

@Service 
public class HelloService { 
//์‹ค์ œ HelloBean ๊ฐ์ฒด๊ฐ€ ์•„๋‹Œ ๊ฐ€์งœ ํ”„๋ก์‹œ ๊ฐ์ฒด
	@Autowired HelloBean helloBean; 

	public void method() { 
    //์‹ค์ œ ์š”์ฒญ์ด ์ผ์–ด๋‚  ๋•Œ ํ”„๋ก์‹œ ๊ฐ์ฒด๋Š” ์‹ค์ œ HelloBean์˜ ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•ด์ค€๋‹ค. 
    helloBean.hello(); 
    } 
}

printProxyBean() ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•ด๋ณด๋ฉด ์ž๋™ ์˜์กด ์ฃผ์ž…์„ ํ†ตํ•ด ๋ฐ›์€ HelloBean๊ฐ์ฒด๋Š” ๊ฐ€์งœ ํ”„๋ก์‹œ ๊ฐ์ฒด์ž„์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค.

//printProxyBean ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ ๊ฒฐ๊ณผ 
ProxyHelloBean: HelloBean$$EnhancerBySpringCGLIB$$35c7aa62
RealHelloBean: HelloBean

request scope ํ”„๋ก์‹œ ํŠน์ง•

ํ”„๋ก์‹œ ๊ฐ์ฒด ๋•๋ถ„์— ํด๋ผ์ด์–ธํŠธ๋Š” ๋งˆ์น˜ ์‹ฑ๊ธ€ํ†ค ๋นˆ์„ ์‚ฌ์šฉํ•˜๋“ฏ์ด ํŽธ๋ฆฌํ•˜๊ฒŒ request scope๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

์‚ฌ์‹ค Provider๋ฅผ ์‚ฌ์šฉํ•˜๋“ , ํ”„๋ก์‹œ๋ฅผ ์‚ฌ์šฉํ•˜๋“  ํ•ต์‹ฌ ์•„์ด๋””์–ด๋Š” ์ง„์งœ ๊ฐ์ฒด ์กฐํšŒ๋ฅผ ๊ผญ ํ•„์š”ํ•œ ์‹œ์ ๊นŒ์ง€ โœ… ์ง€์—ฐ์ฒ˜๋ฆฌ ํ•œ๋‹ค๋Š” ์ ์ด๋‹ค.

๋‹จ์ง€ ์• ๋…ธํ…Œ์ด์…˜ ์„ค์ • ๋ณ€๊ฒฝ๋งŒ์œผ๋กœ ์›๋ณธ ๊ฐ์ฒด๋ฅผ ํ”„๋ก์‹œ ๊ฐ์ฒด๋กœ ๋Œ€์ฒดํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด๊ฒƒ์ด ๋ฐ”๋กœ ๋‹คํ˜•์„ฑ๊ณผ DI ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ๊ฐ€์ง„ ํฐ ๊ฐ•์ ์ด๋‹ค.

๊ผญ ์›น์Šค์ฝ”ํ”„๊ฐ€ ์•„๋‹ˆ์–ด๋„ ํ”„๋ก์‹œ๋Š” ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.


๐Ÿ’ฅ CGLIB ์ œ์•ฝ -> final

ํด๋ž˜์Šค ๊ธฐ๋ฐ˜ ํ”„๋ก์‹œ๋Š” ์ƒ์†์„ ์‚ฌ์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋ช‡๊ฐ€์ง€ ์ œ์•ฝ์ด ์žˆ๋‹ค.

  • ๋ถ€๋ชจ ํด๋ž˜์Šค์˜ ์ƒ์„ฑ์ž๋ฅผ ์ฒดํฌํ•ด์•ผ ํ•œ๋‹ค. CGLIB๋Š” ์ž์‹ ํด๋ž˜์Šค๋ฅผ ๋™์ ์œผ๋กœ ์ƒ์„ฑํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๊ธฐ๋ณธ์ƒ์„ฑ์ž๊ฐ€ ํ•„์š”ํ•˜๋‹ค.
  • ํด๋ž˜์Šค์— final ํ‚ค์›Œ๋“œ๊ฐ€ ๋ถ™์œผ๋ฉด ์ƒ์†์ด ๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค. CGLIB์—์„œ ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.
  • ๋ฉ”์„œ๋“œ์— final ํ‚ค์›Œ๋“œ๊ฐ€ ๋ถ™์œผ๋ฉด ํ•ด๋‹น ๋ฉ”์„œ๋“œ๋ฅผ ์˜ค๋ฒ„๋ผ์ด๋”ฉ ํ•  ์ˆ˜ ์—†๋‹ค. => CGLIB์—์„œ๋Š” ํ”„๋ก์‹œ ๋กœ์ง์ด ๋™์ž‘ํ•˜์ง€ ์•Š๋Š”๋‹ค.

โญ ์Šคํ”„๋ง ๋ถ€ํŠธ๊ฐ€ CGLIB๋ฅผ ๊ธฐ๋ณธ ํ”„๋ก์‹œ ๋ฐฉ์‹์œผ๋กœ ์ฑ„ํƒํ•œ ์ด์œ !

  1. ์ธํ„ฐํŽ˜์ด์Šค ์—†์ด๋„ ํ”„๋ก์‹œ ์ƒ์„ฑ ๊ฐ€๋Šฅ
    JDK ๋™์  ํ”„๋ก์‹œ๋Š” ๋ฐ˜๋“œ์‹œ ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ์žˆ์–ด์•ผ๋งŒ ๋™์ž‘ํ•ด. ๋ฐ˜๋ฉด CGLIB๋Š” ํด๋ž˜์Šค๋ฅผ ์ƒ์†ํ•ด์„œ ํ”„๋ก์‹œ๋ฅผ ๋งŒ๋“ค๊ธฐ ๋•Œ๋ฌธ์—, ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ์—†์–ด๋„ ํ”„๋ก์‹œ ์ƒ์„ฑ์ด ๊ฐ€๋Šฅํ•˜์ง€. ์š”์ฆ˜์€ ์ธํ„ฐํŽ˜์ด์Šค ์—†์ด๋„ ๋นˆ์„ ์ •์˜ํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ์•„์ง€๋ฉด์„œ, CGLIB์˜ ์œ ์—ฐ์„ฑ์ด ๋” ๋น›์„ ๋ฐœํ•˜๊ฒŒ ๋์–ด.

  2. ์„ฑ๋Šฅ ๊ฐœ์„ 
    ์˜ˆ์ „์—๋Š” CGLIB๊ฐ€ ์ƒ๋Œ€์ ์œผ๋กœ ๋А๋ฆฌ๋‹ค๊ณ  ์—ฌ๊ฒจ์กŒ์ง€๋งŒ, JDK ํ”„๋ก์‹œ๋Š” ๋ฆฌํ”Œ๋ ‰์…˜ ๊ธฐ๋ฐ˜์ด๋ผ์„œ ์˜คํžˆ๋ ค ์„ฑ๋Šฅ์ด ๋–จ์–ด์ง€๋Š” ๊ฒฝ์šฐ๋„ ์žˆ์–ด. ํŠนํžˆ ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ์ด ๋นˆ๋ฒˆํ•œ ๊ฒฝ์šฐ์—” CGLIB๊ฐ€ ๋” ๋‚˜์€ ์„ฑ๋Šฅ์„ ๋ณด์ด๊ธฐ๋„ ํ•ด.

  3. Spring Boot์˜ ์ž๋™ ๊ตฌ์„ฑ ์ฒ ํ•™๊ณผ ์ž˜ ๋งž์Œ
    ์Šคํ”„๋ง ๋ถ€ํŠธ๋Š” ๊ฐœ๋ฐœ์ž๊ฐ€ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ผญ ๋งŒ๋“ค์ง€ ์•Š์•„๋„ ๋น ๋ฅด๊ฒŒ ๊ฐœ๋ฐœํ•  ์ˆ˜ ์žˆ๋„๋ก ์„ค๊ณ„๋์ž–์•„. ๊ทธ๋ž˜์„œ ์ธํ„ฐํŽ˜์ด์Šค ์œ ๋ฌด์— ์ƒ๊ด€์—†์ด ์ผ๊ด€๋œ ๋ฐฉ์‹์œผ๋กœ ํ”„๋ก์‹œ๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋Š” CGLIB๊ฐ€ ๋” ์ž์—ฐ์Šค๋Ÿฌ์šด ์„ ํƒ์ด ๋œ ๊ฑฐ์•ผ.

  4. ์˜์กด์„ฑ ๋ฌธ์ œ ํ•ด๊ฒฐ
    ์˜ˆ์ „์—๋Š” CGLIB๊ฐ€ ์™ธ๋ถ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜€๊ธฐ ๋•Œ๋ฌธ์— ์‹ ๋ขฐ์„ฑ์ด๋‚˜ ์˜์กด์„ฑ ๊ด€๋ฆฌ ์ธก๋ฉด์—์„œ ๋ถ€๋‹ด์ด ์žˆ์—ˆ์ง€๋งŒ, Spring 3.2๋ถ€ํ„ฐ๋Š” spring-core์— ๋‚ด์žฅ๋˜๋ฉด์„œ ์ด๋Ÿฐ ๋ฌธ์ œ๊ฐ€ ์‚ฌ๋ผ์กŒ์–ด.

๋ฌผ๋ก  ์—ฌ์ „ํžˆ spring.aop.proxy-target-class=false ์„ค์ •์„ ํ†ตํ•ด JDK ํ”„๋ก์‹œ๋กœ ๋ฐ”๊ฟ€ ์ˆ˜๋„ ์žˆ์–ด. ํ•˜์ง€๋งŒ ์š”์ฆ˜์€ ๋Œ€๋ถ€๋ถ„์˜ ๊ฒฝ์šฐ CGLIB๊ฐ€ ๋” ์‹ค์šฉ์ ์ด๋ผ ๊ธฐ๋ณธ๊ฐ’์œผ๋กœ ์ž๋ฆฌ ์žก์€ ๊ฒƒ์ด๋‹ค.


๊ทธ์™ธ ํ”„๋ก์‹œ๋ฅผ ํ™œ์šฉํ•œ ๊ธฐ์ˆ 

JPA Lazy loading

Jpa ์กฐํšŒ๊ธฐ๋Šฅ ์ค‘ lazy loading ์„ ํ†ตํ•ด proxy๋กœ ํ˜ธ์ถœ


Spring AOP Advice(ํ”„๋ก์‹œ ํŒฉํ† ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด)

Advice๋Š” ํ”„๋ก์‹œ์— ์ ์šฉํ•˜๋Š” ๋ถ€๊ฐ€ ๊ธฐ๋Šฅ ๋กœ์ง์ด๋‹ค.
์ด๊ฒƒ์€ JDK ๋™์  ํ”„๋ก์‹œ๊ฐ€ ์ œ๊ณตํ•˜๋Š” InvocationHandler ์™€
CGLIB๊ฐ€ ์ œ๊ณตํ•˜๋Š” MethodInterceptor ์˜ ๊ฐœ๋…๊ณผ ์œ ์‚ฌํ•œ๋‹ค.

๋‘˜์„ ๊ฐœ๋…์ ์œผ๋กœ ์ถ”์ƒํ™” ํ•œ ๊ฒƒ์ด๋‹ค. ํ”„๋ก์‹œ ํŒฉํ† ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋‘˜ ๋Œ€์‹ ์— Advice๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋œ๋‹ค.

  • @Transactional ์•„๋…ธํ…Œ์ด์…˜์ด ๋Œ€ํ‘œ์ ์ธ ์˜ˆ

์ž์„ธํ•œ ๊ฑด ์ด ๋ธ”๋กœ๊ทธ ์ฐธ์กฐ
https://velog.io/@mooh2jj/์Šคํ”„๋ง-ํŠธ๋žœ์žญ์…˜-AOP-์ดํ•ด

@Transactional ์„ ์‚ฌ์šฉํ•˜๋ฉด ์Šคํ”„๋ง์˜ ํŠธ๋žœ์žญ์…˜ AOP๊ฐ€ ์ ์šฉ๋œ๋‹ค.
ํŠธ๋žœ์žญ์…˜ AOP๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ํ”„๋ก์‹œ(Proxy) ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•œ๋‹ค.

๊ฐ„๋‹จํžˆ ์ •๋ฆฌํ•˜์ž๋ฉด,

@Transactional ์„ ์ ์šฉํ•˜๋ฉด ํ”„๋ก์‹œ ๊ฐ์ฒด๊ฐ€ ์š”์ฒญ์„ ๋จผ์ € ๋ฐ›์•„์„œ(์œ„์ž„) ํŠธ๋žœ์žญ์…˜์„ ๋Œ€์‹  ์ฒ˜๋ฆฌํ•˜๊ณ , ์‹ค์ œ ๊ฐ์ฒด๋ฅผ ํ˜ธ์ถœํ•ด์ฃผ๋Š” ๊ฒƒ์ด๋‹ค.

์ด ๋ฐ–์— @Cachable, @Async ๋„ ์žˆ๋‹ค.


์ฐธ๊ณ  ๋ธ”๋กœ๊ทธ


โญ ๊ทธ๋ž˜๋„ interface๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ด์œ ! -> Jdk ํ”„๋ก์‹œ

Spring Boot 2.x์—์„œ๋Š” AOP ์ ์šฉ ์‹œ ํ”„๋ก์‹œ ๊ฐ์ฒด ์ƒ์„ฑ ๋ฐฉ์‹์ด ๊ธฐ๋ณธ์ ์œผ๋กœ CGLIB(๊ตฌํ˜„ ํด๋ž˜์Šค ๊ธฐ๋ฐ˜) ์œผ๋กœ ๋ฐ”๋€Œ์—ˆ์ง€๋งŒ, ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ด์œ ๋Š” ์—ฌ์ „ํžˆ ๋งŽ๊ณ , ๊ทธ ์ค‘ ํ•˜๋‚˜๊ฐ€ ํ…Œ์ŠคํŠธ์—์„œ ๋” ์œ ๋ฆฌํ•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

1) ์ฝ”๋“œ์˜ ํ™•์žฅ์ด ์‰ฌ์›Œ ์œ ์ง€๋ณด์ˆ˜์„ฑ์ด ์žˆ๋‹ค!

2) ํ…Œ์ŠคํŠธ์ฝ”๋“œ ์ž‘์„ฑ์‹œ, ๋ชฉ๊ฐ์ฒด๋“ค๋กœ ๋ถˆ๋Ÿฌ์™€ ๋” ๋น ๋ฅธ ํ…Œ์ŠคํŠธ์ฝ”๋“œ์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค!

โœ… Mockito ๊ฐ™์€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” ์ธํ„ฐํŽ˜์ด์Šค ๊ธฐ๋ฐ˜์˜ Mock ๊ฐ์ฒด(@Mock, @InjectMock)๋ฅผ ๋” ๋‹จ์ˆœํ•˜๊ฒŒ ์ƒ์„ฑํ•ด์š”. (๋ฌผ๋ก  ํด๋ž˜์Šค๋„ ๊ฐ€๋Šฅํ•˜์ง€๋งŒ ์ œ์•ฝ์ด ์žˆ์–ด์š”)

๊ทธ๋ฆฌ๊ณ  ์ด๋Ÿฌ๋ฉด, ์ธํ„ฐํŽ˜์ด์Šค ๊ธฐ๋ฐ˜ ๊ตฌ์กฐ์—์„œ๋Š” ๋Œ€์ƒ ๊ฐ์ฒด์˜ ์˜์กด์„ฑ๋งŒ Mock ์ฒ˜๋ฆฌํ•ด, ๋‹จ์œ„ ํ…Œ์ŠคํŠธ ๋ฒ”์œ„๋ฅผ ๋ช…ํ™•ํžˆ ์ œ์–ดํ•  ์ˆ˜ ์žˆ์–ด์š”.


๐Ÿ”ฅ ์˜คํ•ดํ•˜๊ธฐ ์‰ฌ์šด ๋ถ€๋ถ„ ์ •๋ฆฌ

๋‚ด์šฉ์„ค๋ช…
CGLIB ๊ธฐ๋ฐ˜์ด๋ผ ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ๋ฌด์˜๋ฏธํ•˜๋‹ค?โŒ ์ธํ„ฐํŽ˜์ด์Šค ์—†์œผ๋ฉด CGLIB ์“ฐ๋Š” ๊ฑฐ๊ณ , ์žˆ์œผ๋ฉด ์—ฌ์ „ํžˆ JDK Proxy๋ฅผ ์šฐ์„  ์‹œ๋„ํ•ด์š”
ํ…Œ์ŠคํŠธ ์ฝ”๋“œ์—์„œ ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ๊ผญ ํ•„์š”ํ•˜๋‹ค?โœ… ์ธํ„ฐํŽ˜์ด์Šค ๊ธฐ๋ฐ˜์ด๋ฉด ํ…Œ์ŠคํŠธ ์ž‘์„ฑ์ด ๋” ์œ ๋ฆฌํ•˜๊ณ  ๊น”๋”ํ•œ ๊ตฌ์กฐ๋กœ ๊ฐ€๋Šฅํ•ด์š”
๊ตฌํ˜„ ํด๋ž˜์Šค๋„ Mock ๊ฐ€๋Šฅํ•˜๋‹ค?โœ… ๊ฐ€๋Šฅํ•˜์ง€๋งŒ, final ํด๋ž˜์Šค/๋ฉ”์„œ๋“œ ๋“ฑ ์ œ์•ฝ ์กด์žฌ

Spring Boot 2.x์—์„œ AOP์šฉ ํ”„๋ก์‹œ๊ฐ€ CGLIB ๊ธฐ๋ฐ˜์œผ๋กœ ๋ฐ”๋€Œ์—ˆ๋”๋ผ๋„, ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ํ…Œ์ŠคํŠธ ์ฝ”๋“œ ์ž‘์„ฑ ์‹œ Mock ๊ฐ์ฒด๋ฅผ ๋” ์‰ฝ๊ฒŒ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ์–ด ๋น ๋ฅด๊ณ  ์•ˆ์ •์ ์ธ ๋‹จ์œ„ ํ…Œ์ŠคํŠธ๊ฐ€ ๊ฐ€๋Šฅํ•˜๋‹ค.

class๋กœ service๋ฅผ ๋งŒ๋“ค์‹œ,


class OrderService {
    private final PaymentService paymentService = new PaymentService();

    public boolean processOrder(int amount) {
        return paymentService.pay(amount);
    }
}

@Test
void processOrder_realPaymentService() {
    OrderService orderService = new OrderService();

    boolean result = orderService.processOrder(1000);

    assertThat(result).isTrue(); // ์‹ค์ œ ๊ฒฐ์ œ ๋กœ์ง์ด ์‹คํ–‰๋จ
}

interface๋กœ service ๋งŒ๋“  ๋ฐฉ์‹

public interface PaymentService {
    boolean pay(int amount);
}

public class OrderService {
    private final PaymentService paymentService;

    public OrderService(PaymentService paymentService) {
        this.paymentService = paymentService;
    }

    public boolean processOrder(int amount) {
        return paymentService.pay(amount);
    }
}
@Test
void processOrder_mockedPaymentService() {
    // PaymentService -> Mock๊ฐ์ฒด๋กœ  
    PaymentService mockPaymentService = amount -> amount < 5000;
    OrderService orderService = new OrderService(mockPaymentService);

    boolean result = orderService.processOrder(3000);

    assertThat(result).isTrue(); // ๋กœ์ง๋งŒ ๊ฒ€์ฆ ๊ฐ€๋Šฅ
}

๊ฒฐ๋ก !

๐Ÿ“Œ ๊ตฌํ˜„ ํด๋ž˜์Šค๋กœ DIํ•˜์ง€ ๋ง์ž! ์ธํ„ฐํŽ˜์ด์Šค๋กœ ํ•˜์ž!

@ExtendWith(MockitoExtension.class)
class OrderServiceTest {

	// PaymentService ๊ตฌํ˜„ํด๋ž˜์Šค
    @Mock
    PaymentService paymentService; // โš ๏ธ final ๋ถ™์—ฌ์ง„ ํด๋ž˜์Šค๋ผ๋ฉด, ๋ฌธ์ œ ๋ฐœ์ƒ ๊ฐ€๋Šฅ

    @InjectMocks
    OrderService orderService;  

    @Test
    void test() {
	 // โŒ ๋Ÿฐํƒ€์ž„ ์˜ค๋ฅ˜ ๋ฐœ์ƒ ๊ฐ€๋Šฅ
 	when(paymentServiceImpl.pay(anyInt())).thenReturn(true);
        
    }
}

๐Ÿ’ก๊ทธ๋Ÿฌ๋ฉด ์Šคํ”„๋ง๋ถ€ํŠธ์˜ ์–ด๋…ธํ…Œ์ด์…˜๋“ค์€ ์ „๋ถ€ ํ”„๋ก์‹œ๊ธฐ๋ฐ˜์œผ๋กœ ๋™์ž‘?

๊ฒฐ๋ก ์€ ์•„๋‹ˆ์•ผ! ํ•˜์ง€๋งŒ ๋Œ€๋ถ€๋ถ„์˜ ์–ด๋…ธํ…Œ์ด์…˜๋“ค์ด ๊ทธ๋ž˜!

์Šคํ”„๋ง ๋ถ€ํŠธ์—์„œ ์–ด๋…ธํ…Œ์ด์…˜๋“ค์ด ๋™์ž‘ํ•˜๋Š” ๋ฐฉ์‹์„ ๋ณด๋ฉด, ๋งŽ์€ ๊ฒฝ์šฐ ํ”„๋ก์‹œ ๊ธฐ๋ฐ˜์œผ๋กœ ๋™์ž‘ํ•œ๋‹ค๊ณ  ๋ณผ ์ˆ˜ ์žˆ์–ด.

ํŠนํžˆ AOP(Aspect-Oriented Programming) ๊ธฐ๋Šฅ์„ ํ™œ์šฉํ•˜๋Š” ์–ด๋…ธํ…Œ์ด์…˜๋“คโ€”์˜ˆ๋ฅผ ๋“ค๋ฉด @Transactional, @Async, @Cacheable ๊ฐ™์€ ๊ฒƒ๋“คโ€”์€ ๋‚ด๋ถ€์ ์œผ๋กœ ํ”„๋ก์‹œ๋ฅผ ์ƒ์„ฑํ•ด์„œ ๋™์ž‘์„ ๊ฐ€๋กœ์ฑ„๋Š” ๋ฐฉ์‹์œผ๋กœ ๊ตฌํ˜„๋ผ.

ํ•˜์ง€๋งŒ ๋ชจ๋“  ์–ด๋…ธํ…Œ์ด์…˜์ด ํ”„๋ก์‹œ ๊ธฐ๋ฐ˜์ธ ๊ฑด ์•„๋‹ˆ์•ผ. ์˜ˆ๋ฅผ ๋“ค์–ด @RestController, @GetMapping ๊ฐ™์€ ์–ด๋…ธํ…Œ์ด์…˜์€ ํ”„๋ก์‹œ๋ณด๋‹ค๋Š” ๋ฆฌํ”Œ๋ ‰์…˜ ๊ธฐ๋ฐ˜์˜ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ์— ๊ฐ€๊น๊ณ , ์Šคํ”„๋ง์ด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์‹œ์ž‘ ์‹œ์ ์— ์ด๋ฅผ ์Šค์บ”ํ•ด์„œ ๊ด€๋ จ ์„ค์ •์„ ๋“ฑ๋กํ•˜๋Š” ์‹์œผ๋กœ ๋™์ž‘ํ•ด.

์ฆ‰, "๋Œ€๋ถ€๋ถ„ ํ”„๋ก์‹œ ๊ธฐ๋ฐ˜์ด๋‹ค"๋ผ๊ณ  ์ƒ๊ฐํ•ด๋„ ํฌ๊ฒŒ ํ‹€๋ฆฌ์ง„ ์•Š์ง€๋งŒ, AOP๋‚˜ DI(์˜์กด์„ฑ ์ฃผ์ž…) ๊ฐ™์€ ์˜์—ญ์—์„œ ํŠนํžˆ ๊ทธ๋ ‡๊ณ , ์ผ๋ถ€ ์–ด๋…ธํ…Œ์ด์…˜์€ ๋‹ค๋ฅธ ๋ฐฉ์‹์œผ๋กœ ๋™์ž‘ํ•œ๋‹ค!


ํšก๋‹จ๊ด€์‹ฌ(๊ณตํ†ต ๋ชจ๋“ˆ)

ํšก๋‹น๊ด€์‹ฌ์œผ๋กœ ๋ญ๊ฐ€ ์žˆ์„๊นŒ?

ex. ๋กœ๊น…, ์‹œ๊ฐ„์ธก์ •, ๋ณด์•ˆ, ํŠธ๋žœ์žญ์…˜ ๋“ฑ


์ถœ์ฒ˜: https://expert0226.tistory.com/200 [์—ฌ๋ฆ„๋‚˜๋ผ๊ฒจ์šธ์ด์•ผ๊ธฐ]

๋งŒ์•ฝ, ๋ชจ๋“  ๋ฉ”์„œ๋“œ์˜ ํ˜ธ์ถœ ์‹œ๊ฐ„์„ ์ธก์ •ํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด?

@Component
@Aspect
public class TimeTraceAop {

    /**
     * AOP ์„ค์ •
     * @param joinPoint ์‹คํ–‰ํ•  ๋ฉ”์†Œ๋“œ
     * @return ์‹คํ–‰ ๊ฒฐ๊ณผ
     * @throws Throwable ์˜ˆ์™ธ ๋ฐœ์ƒ ์‹œ
     */
    @Around("execution(* com.dsg.mallapi..*(..))")
    public Object execute(ProceedingJoinPoint joinPoint) throws Throwable {
        long start = System.currentTimeMillis();
        System.out.println("START: " + joinPoint.toString());
        try {
            return joinPoint.proceed();
        } finally {
            long finish = System.currentTimeMillis();
            long timeMs = finish - start;
            System.out.println("END: " + joinPoint.toString() + " " + timeMs + "ms");
        }
    }

}


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

/**
 * ์‹œ๊ฐ„ ์ธก์ • AOP
 * ๋ฉ”์„œ๋“œ๋งˆ๋‹ค ์ ์šฉ
 */
@Component
@Aspect
public class TimeTraceAop {


    /**
     * AOP ์„ค์ •
     * @param joinPoint ์กฐ์ธ ํฌ์ธํŠธ
     * @return ์‹คํ–‰ ๊ฒฐ๊ณผ
     * @throws Throwable ์˜ˆ์™ธ ๋ฐœ์ƒ ์‹œ
     */

//    execution(* com.dsg.mallapi..*(..))
    @Pointcut("execution(* com.dsg.mallapi..*(..))")
    private void timeTracePointcut() {}


    @Around("timeTracePointcut()")
    public Object execute(ProceedingJoinPoint joinPoint) throws Throwable {
        long start = System.currentTimeMillis();
        System.out.println("START: " + joinPoint.toString());
        try {
            return joinPoint.proceed();
        } finally {
            long finish = System.currentTimeMillis();
            long timeMs = finish - start;
            System.out.println("END: " + joinPoint.toString() + " " + timeMs + "ms");
        }
    }

}
  • โœจ Aspect : ๋ชจ๋“ˆ
    - Advice์™€ Pointcut์˜ ์กฐํ•ฉ

    • ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ๊ฐ€์ง€๊ณ  ์žˆ์–ด์•ผ ํ•  ๋กœ์ง๊ณผ ๊ทธ๊ฒƒ์„ ์‹คํ–‰ํ•ด์•ผ ํ•˜๋Š” ์ง€์ ์„ ์ •์˜ํ•œ ๊ฒƒ, Aspect๋Š” ํ•ต์‹ฌ๋กœ์ง๊ณผ ๋–จ์–ด์ง„ ๋ถ€๊ฐ€๊ธฐ๋Šฅ์„ ์˜๋ฏธํ•˜๋Š” ๋ฐ ์“ฐ์ธ๋‹ค.
    • @Aspect : ํด๋ž˜์Šค์— AOP ์„ค์ •์„ ๋ถ™์—ฌ์ฃผ๋Š” ์–ด๋…ธํ…Œ์ด์…˜
  • โœจ JointPoint : ํ•ฉ๋ฅ˜ ์ง€์ , ๋ฉ”์†Œ๋“œ ์‹คํ–‰์‹œ์ 
    - ํšก๋‹จ ๊ณตํ†ต(Crosscutting Concerns) ๋ชจ๋“ˆ์ด ์‚ฝ์ž…๋˜์–ด ๋™์ž‘ํ•  ์ˆ˜ ์žˆ๋Š” ์‹คํ–‰ ๊ฐ€๋Šฅํ•œ ํŠน์ • ์œ„์น˜
    - ๋ฉ”์†Œ๋“œ ํ˜ธ์ถœ, ๋ฉ”์†Œ๋“œ ์‹คํ–‰ ์ž์ฒด, ํด๋ž˜์Šค ์ดˆ๊ธฐํ™”, ๊ฐ์ฒด ์ƒ์„ฑ ์‹œ์  ๋“ฑ

  • โœจPointcut: ์–ด๋–ค ํฌ์ธํŠธ(Point)์— ๊ธฐ๋Šฅ์„ ์ ์šฉํ• ์ง€ ํ•˜์ง€ ์•Š์„์ง€ ์ž˜๋ผ์„œ(cut) ๊ตฌ๋ถ„ํ•˜๋Š” ๊ฒƒ์ด๋‹ค.
    - Pointcut์€ ์–ด๋–ค ํด๋ž˜์Šค์˜ ์–ด๋А JoinPoint๋ฅผ ์‚ฌ์šฉํ•  ๊ฒƒ์ธ์ง€๋ฅผ ๊ฒฐ์ •ํ•˜๋Š” ํ•„ํ„ฐ ํŒจํ„ด

    • ๊ฐ€์žฅ ์ผ๋ฐ˜์ ์ธ Pointcut์€ โ€˜ํŠน์ • ํด๋ž˜์Šค์— ์žˆ๋Š” ๋ชจ๋“  ๋ฉ”์†Œ๋“œ ํ˜ธ์ถœโ€™๋กœ ๊ตฌ์„ฑ
  • โœจ Around : ๋Œ€์ƒ ๋ฉ”์„œ๋“œ์˜ ์‹คํ–‰ ์ „ํ›„์— Aspect๊ฐ€ ์ ์šฉ๋  ์ˆ˜ ์žˆ๊ฒŒ ๋„์™€์ค€๋‹ค.

    • @Around ์–ด๋“œ๋ฐ”์ด์Šค๋Š” ๋Œ€์ƒ ๋ฉ”์„œ๋“œ์˜ ์‹คํ–‰์„ ๊ฐ์‹ธ์„œ ์ „/ํ›„ ์ฒ˜๋ฆฌ๋ฅผ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • โœจ Advice : ํ”„๋ก์‹œ๊ฐ€ ํ˜ธ์ถœํ•˜๋Š” ์กฐ์–ธ(๋ถ€๊ฐ€ ๊ธฐ๋Šฅ) ๋‹จ์ˆœํ•˜๊ฒŒ ํ”„๋ก์‹œ ๋กœ์ง์ด๋ผ ์ƒ๊ฐํ•˜๋ฉด ๋œ๋‹ค.
    - Advice๋Š” ๊ด€์ (Aspect)์˜ ์‹ค์ œ ๊ตฌํ˜„์ฒด๋กœ ๊ฒฐํ•ฉ์ ์— ์‚ฝ์ž…๋˜์–ด ๋™์ž‘ํ•  ์ˆ˜ ์žˆ๋Š” ์ฝ”๋“œ

    • Advice ๋Š” ๊ฒฐํ•ฉ์ (JoinPoint)๊ณผ ๊ฒฐํ•ฉํ•˜์—ฌ ๋™์ž‘ํ•˜๋Š” ์‹œ์ ์— ๋”ฐ๋ผ before advice, after advice, around advice ํƒ€์ž…์œผ๋กœ ๊ตฌ๋ถ„
    • ํŠน์ • JoinPoint์— ์‹คํ–‰ํ•˜๋Š” ์ฝ”๋“œ
  • Advisor : ๋‹จ์ˆœํ•˜๊ฒŒ ํ•˜๋‚˜์˜ ํฌ์ธํŠธ์ปท๊ณผ ํ•˜๋‚˜์˜ ์–ด๋“œ๋ฐ”์ด์Šค๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ๊ฒƒ์ด๋‹ค. ์‰ฝ๊ฒŒ ์ด์•ผ๊ธฐํ•ด์„œ Pointcut + Advice์ด๋‹ค.

  • Weaving :
    - Pointcut์œผ๋กœ ์ง€์ •ํ•œ ํ•ต์‹ฌ ๊ด€์‹ฌ ๋ฉ”์†Œ๋“œ๊ฐ€ ํ˜ธ์ถœ๋  ๋•Œ, ์–ด๋“œ๋ฐ”์ด์Šค์— ํ•ด๋‹นํ•˜๋Š” ํšก๋‹จ ๊ด€์‹ฌ ๋ฉ”์†Œ๋“œ๊ฐ€ ์‚ฝ์ž…๋˜๋Š” ๊ณผ์ •.
    - Weaving์„ ํ†ตํ•ด์„œ ๋น„์ฆˆ๋‹ˆ์Šค ๋ฉ”์†Œ๋“œ๋ฅผ ์ˆ˜์ •ํ•˜์ง€ ์•Š๊ณ ๋„ ํšก๋‹จ ๊ด€์‹ฌ์— ํ•ด๋‹นํ•˜๋Š” ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•˜๊ฑฐ๋‚˜ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ๋‹ค.

์ฆ‰, AOP๋Š”

JoinPoint๋ฅผ ์‹คํ–‰ โ†’ Pointcut์œผ๋กœ ์ง€์ •ํ•œ ๋ฉ”์†Œ๋“œ๊ฐ€ ํ˜ธ์ถœ๋˜๋Š” ์ˆœ๊ฐ„ Advice ๋ฉ”์†Œ๋“œ๊ฐ€ ์‹คํ–‰
Advice ๋ฉ”์†Œ๋“œ ์‚ฝ์ž…โ†’ Aspect ์„ค์ •์— ๋”ฐ๋ผ Weaving ์ฒ˜๋ฆฌ.


์ฃผ์š” ์–ด๋…ธํ…Œ์ด์…˜

@Timer

โœจ@Aspect : ์ž๋ฐ”์—์„œ ๋„๋ฆฌ ์‚ฌ์šฉํ•˜๋Š” AOP ํ”„๋ ˆ์ž„์›Œํฌ์— ํฌํ•จ๋˜๋ฉฐ, AOP๋ฅผ ์ •์˜ํ•˜๋Š” class์— ํ•ด๋‹น

โœจ@Pointcut : ๊ธฐ๋Šฅ์„ ์–ด๋””์— ์ ์šฉ์‹œํ‚ฌ์ง€, ๋ฉ”์†Œ๋“œ? Annotation? ๋“ฑ AOP๋ฅผ ์ ์šฉ์‹œํ‚ฌ ์ง€์ ์„ ๊ฒฐ์ •

โœจ @Around : Before / after ๋ชจ๋‘ ์ œ์–ด

@Before : ๋ฉ”์†Œ๋“œ ์‹คํ–‰ํ•˜๊ธฐ ์ด์ „
@After : ๋ฉ”์†Œ๋“œ๊ฐ€ ์„ฑ๊ณต์ ์œผ๋กœ ์‹คํ–‰ ํ›„, ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒ๋˜๋”๋ผ๋„ ์‹คํ–‰
@AfterReturing : ๋ฉ”์†Œ๋“œ ํ˜ธ์ถœ ์„ฑ๊ณต ์‹คํ–‰ ์‹œ (Not Throws)
@AfterThrowing : ๋ฉ”์†Œ๋“œ ํ˜ธ์ถœ ์‹คํŒจ ์˜ˆ์™ธ ๋ฐœ์ƒ (Throws)


AOP ๋™์ž‘ ๊ณผ์ •

1) Before Advice : ํฌ์ธํŠธ์ปท์œผ๋กœ ์ง€์ •๋œ ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœ ์‹œ ๋ฉ”์†Œ๋“œ๊ฐ€ ์‹คํ–‰๋˜๊ธฐ ์ „์— ์ฒ˜๋ฆฌํ•  ๋‚ด์šฉ์„ ๊ธฐ์ˆ ํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ

2) After Returning Advice : ํฌ์ธํŠธ์ปท์œผ๋กœ ์ง€์ •๋œ ๋ฉ”์†Œ๋“œ๊ฐ€ ์ •์ƒ์ ์œผ๋กœ ์‹คํ–‰๋˜๊ณ  ๋‚˜์„œ, ๋ฉ”์†Œ๋“œ ์ˆ˜ํ–‰ ๊ฒฐ๊ณผ๋กœ ์ƒ์„ฑ๋œ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฆฌํ„ดํ•˜๋Š” ์‹œ์ ์— ๋™์ž‘. ๋น„์ง€๋‹ˆ์Šค ๋ฉ”์†Œ๋“œ์˜ ๊ฒฐ๊ณผ๋กœ ์–ป์€ ๊ฒฐ๊ณผ ๋ฐ์ดํ„ฐ๋ฅผ ์ด์šฉํ•˜์—ฌ ์‚ฌํ›„ ๋กœ์ง์„ ์ถ”๊ฐ€ํ•  ๋•Œ ์‚ฌ์šฉ๋œ๋‹ค.

3) After Throwing Advice : ํฌ์ธํŠธ์ปท์œผ๋กœ ์ง€์ •ํ•œ ๋ฉ”์†Œ๋“œ๊ฐ€ ์‹คํ–‰๋˜๋‹ค๊ฐ€ ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ์‹œ์ ์— ๋™์ž‘. ์˜ˆ์™ธ ์ฒ˜๋ฆฌ ์–ด๋“œ๋ฐ”์ด์Šค๋ฅผ ์„ค์ •ํ•  ๋•Œ ์‚ฌ์šฉํ•œ๋‹ค.

4) After Advice : ์˜ˆ์™ธ ๋ฐœ์ƒ ์—ฌ๋ถ€์— ์ƒ๊ด€์—†์ด ๋ฌด์กฐ๊ฑด ์ˆ˜ํ–‰๋˜๋Š” ์–ด๋“œ๋ฐ”์ด์Šค๋ฅผ ๋“ฑ๋กํ•  ๋•Œ ์‚ฌ์šฉ.

5) Around Advice : ๋‹ค๋ฅธ Advice๋Š” ์‹คํ–‰ ์ „/ํ›„์˜ ์ˆ˜ํ–‰๋˜๋Š” ์ฒ˜๋ฆฌ๋ฅผ ์œ„ํ•ด์„œ ์„ค์ •ํ–ˆ๋‹ค๋ฉด Around Advice๋Š” ํด๋ผ์ด์–ธํŠธ์˜ ๋ฉ”์†Œ๋“œ ํ˜ธ์ถœ์„ ๊ฐ€๋กœ์ฑˆ ๋’ค ์‹คํ–‰ ์ „/ํ›„์˜ ์ฒ˜๋ฆฌ๋ฅผ ๋™์‹œ์— ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.


AOP ํ™œ์šฉ ์˜ˆ์‹œ



์ฐธ๊ณ 

  • ๊น€์˜ํ•œ AOP ๊ณ ๊ธ‰ ๊ฐ•์˜
  • ํŒจ์ŠคํŠธ์บ ํผ์Šค ์Šคํ”„๋ง ๊ฐ•์˜
  • https://soft91.tistory.com/69 [๋„ˆ์™€ ๋‚˜์˜ ํ”„๋กœ๊ทธ๋ž˜๋ฐ]
  • https://expert0226.tistory.com/200 [์—ฌ๋ฆ„๋‚˜๋ผ๊ฒจ์šธ์ด์•ผ๊ธฐ]
profile
๋ฐฐ์šด ๊ฒƒ์„ ๊ธฐ๋กํ•ฉ๋‹ˆ๋‹ค.

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