: ๊ด์ ์งํฅ
ํ๋ก๊ทธ๋๋ฐ
์คํ๋ง ์ดํ๋ฆฌ์ผ์ด์ ์ ๋๋ถ๋ถ ํน๋ณํ ๊ฒฝ์ฐ๋ฅผ ์ ์ธํ๊ณ ๋ MVC ์น ์ดํ๋ฆฌ์ผ์ด์ ์์๋ Web Layer, Business Layer, Data Layer ๋ก ์ ์.
์คํ๋ง DI๊ฐ ์์กด์ฑ(new) ์ฃผ์ ์ด๋ผ๋ฉด,
โญ ์คํ๋ง AOP๋
๋ก์ง(code) ์ฃผ์
์ด๋ผ๊ณ ๋ณผ ์ ์๋ค.
๋ก๊น
, ๋ณด์
, ํธ๋์ญ์
, validation
๋ฑ๋ฑ ๊ณตํต๋ ๊ธฐ๋ฅ์ ๋ชจ์๋์ ๋ฐ๋ณต์ ์ผ๋ก ๋ํ๋๋ ๋ถ๋ถ์ด ์๋๋ฐ ์ด๋ฅผ ํก๋จ๊ด์ฌ(cross-cutting concern)์ด๋ผ๊ณ ํ๋ค.
โจ AOP๋ ํต์ฌ ๋น์ฆ๋์ค ๋ก์ง์ ์ํฅ์ ๋ฐ๊ฒ ํ์ง ์๊ณ ๋ฐ๋ณต์ ์ธ ๊ณตํต ๋ถ๋ถ์
๋ชจ๋ํ
ํด ๋ชฐ์์ฃผ๋ ๊ธฐ์ ์ด๋ค.
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 ๋์ ํ๋ก์๋ ์๋ฐ์์ ์ ๊ณตํ๋ ๊ธฐ๋ณธ์ ์ธ ํ๋ก์ ๊ธฐ์ ์
๋๋ค.
์๋ฐ์ โญ ์ธํฐํ์ด์ค๋ฅผ ๊ธฐ๋ฐ
์ผ๋ก ๋์ํ๋ฉฐ, ์ธํฐํ์ด์ค์ ๊ตฌํ ํด๋์ค๋ฅผ ์๋์ผ๋ก ์์ฑํ์ฌ ํ๋ก์ ๊ฐ์ฒด๋ฅผ ์์ฑ
ํฉ๋๋ค. ์ธํฐํ์ด์ค์ ๋ฉ์๋๋ฅผ ํธ์ถํ๋ฉด ํ๋ก์ ๊ฐ์ฒด๋ InvocationHandler๋ฅผ ํตํด ํด๋น ๋ฉ์๋๋ฅผ ํธ์ถํ๊ณ ๋ถ๊ฐ ๊ธฐ๋ฅ์ ์ถ๊ฐํฉ๋๋ค.
JDK ๋์ ํ๋ก์ ๊ธฐ์ ์ ์ฌ์ฉํ๋ฉด ๊ฐ๋ฐ์๊ฐ ์ง์ ํ๋ก์ ํด๋์ค๋ฅผ ๋ง๋ค์ง ์์๋ ๋๋ค. ์ด๋ฆ ๊ทธ๋๋ก ํ๋ก์ ๊ฐ์ฒด๋ฅผ ๋์ ์ผ๋ก ๋ฐํ์์ ๊ฐ๋ฐ์ ๋์ ๋ง๋ค์ด์ค๋ค.
๊ทธ๋ฆฌ๊ณ ๋์ ํ๋ก์์ ์ํ๋ ์คํ ๋ก์ง์ ์ง์ ํ ์ ์๋ค.
JDK ๋์ ํ๋ก์ ๊ธฐ์ ๋๋ถ์ ์ ์ฉ ๋์ ๋งํผ ํ๋ก์ ๊ฐ์ฒด๋ฅผ ๋ง๋ค์ง ์์๋ ๋๋ค.
๊ฒฐ๊ณผ์ ์ผ๋ก ํ๋ก์ ํด๋์ค๋ฅผ ์ ์์ด ๋ง๋ค์ด์ผ ํ๋ ๋ฌธ์ ๋ ํด๊ฒฐํ๊ณ , ๋ถ๊ฐ ๊ธฐ๋ฅ ๋ก์ง๋ ํ๋์ ํด๋์ค์ ๋ชจ์์ ๋จ์ผ ์ฑ ์ ์์น(SRP)๋ ์งํฌ ์ ์๊ฒ ๋์๋ค.
์ ์ฉํ!
* JDK ๋์ ํ๋ก์๋ ์ธํฐํ์ด์ค๊ฐ ํ์์ด๋ค.
JDK ๋์ ํ๋ก์๋ ์๋ฐ์ ๋ฆฌํ๋ ์ ๊ธฐ์ ์ ์ฌ์ฉํ๋ค! ์, ๊ทธ๋ฌ๋ฉด ๋ฆฌํ๋ ์ ๊ธฐ์ ์ ์์๋ณด์!
๋ฆฌํ๋ ์ ์ ๋ฐํ์์ ๋ฉ์๋๋ ํ๋๋ฅผ ์ฐพ์์ ํธ์ถํ๊ธฐ ๋๋ฌธ์ ์ ์ ํธ์ถ๋ณด๋ค ํจ์ฌ ๋๋ฆฌ๊ณ CPU ์์์ ๋ ๋ง์ด ์๋ชจํ๋ค.
์๋ฅผ ๋ค์ด, ํ ๊ฐ๋ฐ์๊ฐ ์ง์ ํ ์คํธํ ๊ฒฐ๊ณผ์ ๋ฐ๋ฅด๋ฉด, ๋์ผํ ๊ฐ์ฒด๋ฅผ 8์ฒ๋ง ๋ฒ ์์ฑํ๊ณ ํ๋๋ฅผ ์ค์ ํ๋ ์์ ์์:
- ๋ฆฌํ๋ ์
์ฌ์ฉ: ์ฝ 42์ด, CPU ์ฌ์ฉ๋ฅ 44%
์ฆ, ์ฝ 8~10๋ฐฐ ๋๋ฆฌ๊ณ CPU ๋ถํ๋ ํจ์ฌ ํผ.
JDK ๋์ ํ๋ก์๋ ๋ด๋ถ์ ์ผ๋ก java.lang.reflect.Proxy
๋ฅผ ์ฌ์ฉํด์ ๋ฉ์๋๋ฅผ ํธ์ถํ ๋๋ง๋ค InvocationHandler.invoke()
๋ฅผ ํตํด ๋ฆฌํ๋ ์
์ผ๋ก ๋ฉ์๋๋ฅผ ์ฐพ์ ์คํํด. ์ด ๊ณผ์ ์ด ๋ฐ๋ณต๋๋ฉด ์ฑ๋ฅ ์ ํ๊ฐ ๋์ ๋๊ธฐ ๋๋ฌธ์, ์คํ๋ง์์๋ CGLIB์ฒ๋ผ ๋ฐ์ดํธ์ฝ๋๋ฅผ ์ง์ ์กฐ์ํด์ ์ ์ ํธ์ถ์ ๊ฐ๊น์ด ๋ฐฉ์์ ์ ํธํ๊ฒ ๋ ๊ฑฐ์ผ.
์ด๋ฐ ์ด์ ๋ก, ์คํ๋ง ๋ถํธ๋ ์ธํฐํ์ด์ค ์ ๋ฌด์ ์๊ด์์ด ๋ ๋น ๋ฅด๊ณ ์ ์ฐํ CGLIB๋ฅผ ๊ธฐ๋ณธ๊ฐ์ผ๋ก ์ฑํํ ๊ฒ์ด๋ค!
์ฐธ๊ณ ๋ก ์ฐ๋ฆฌ๊ฐ CGLIB๋ฅผ ์ง์ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ๋ ๊ฑฐ์ ์๋ค. ์ดํ์ ์ค๋ช ํ ์คํ๋ง์ ProxyFactory ๋ผ๋ ๊ฒ์ด ์ด ๊ธฐ์ ์ ํธ๋ฆฌํ๊ฒ ์ฌ์ฉํ๊ฒ ๋์์ฃผ๊ธฐ ๋๋ฌธ์, ๋๋ฌด ๊น์ด์๊ฒ ํ๊ธฐ ๋ณด๋ค๋ CGLIB๊ฐ ๋ฌด์์ธ์ง ๋๋ต ๊ฐ๋ ๋ง ์ก์ผ๋ฉด ๋๋ค.
https://velog.io/@jaeyeon93/๋ฆฌํ๋ ์ ์-์ผ๋ง๋-๋๋ฆด๊น
CGLIB (Code Generation Library) Proxy๋ JDK Dynamic Proxy์ ๋ฌ๋ฆฌ ์ธํฐํ์ด์ค๊ฐ ์๋ ํด๋์ค๋ฅผ ๊ธฐ๋ฐ
์ผ๋ก ๋์ํฉ๋๋ค.
๋ฐํ์์ ํด๋์ค์ ์๋ธํด๋์ค๋ฅผ ์์ฑํ์ฌ ํ๋ก์ ๊ฐ์ฒด๋ฅผ ์์ฑ
ํฉ๋๋ค.
๐ฅ ๋จ, ์์์ด ๋ถ๊ฐ๋ฅํ final ํด๋์ค๋ private ์์ฑ์๋ฅผ ๊ฐ์ง ํด๋์ค๋ ํ๋ก์ ๊ฐ์ฒด๋ฅผ ์์ฑํ ์ ์์ต๋๋ค.
๋ฉ์๋ ํธ์ถ ์ ํ๋ก์ ๊ฐ์ฒด๋ MethodInterceptor๋ฅผ ํตํด ํด๋น ๋ฉ์๋๋ฅผ ํธ์ถํ๊ณ ๋ถ๊ฐ ๊ธฐ๋ฅ์ ์ถ๊ฐํฉ๋๋ค.
CGLIB
๋ผ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ก ๋ด ํด๋์ค๋ฅผ ์์ ๋ฐ์ ๊ฐ์ง ํ๋ก์ ๊ฐ์ฒด๋ฅผ ๋ง๋ค์ด์ ์ฃผ์
ํ๋ค.
- CGLIB๋ ๋ฐ์ดํธ์ฝ๋๋ฅผ ์กฐ์ํด์ ๋์ ์ผ๋ก ํด๋์ค๋ฅผ ์์ฑํ๋ ๊ธฐ์ ์ ์ ๊ณตํ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ด๋ค.
- CGLIB๋ฅผ ์ฌ์ฉํ๋ฉด ์ธํฐํ์ด์ค๊ฐ ์์ด๋ ๊ตฌ์ฒด ํด๋์ค๋ง ๊ฐ์ง๊ณ ๋์ ํ๋ก์๋ฅผ ๋ง๋ค์ด๋ผ ์ ์๋ค.
- CGLIB๊ฐ ๋์ ์ผ๋ก ์์ฑํ๋ ํด๋์ค ์ด๋ฆ์ ๋ค์๊ณผ ๊ฐ์ ๊ท์น์ผ๋ก ์์ฑ๋๋ค.
๋์ํด๋์ค$$EnhancerByCGLIB$$์์์ฝ๋
์ฐธ๊ณ ๋ก ๋ค์์ JDK Proxy๊ฐ ์์ฑํ ํด๋์ค ์ด๋ฆ์ด๋ค.
proxyClass=class com.sun.proxy.$Proxy1
์ด ๊ฐ์ง ํ๋ก์ ๊ฐ์ฒด๋ ์ค์ ์์ฒญ์ด ์ค๋ฉด ๊ทธ๋ ๋ด๋ถ์์ ์ค์ ๋น์ ์์ฒญํ๋ ์์ ๋ก์ง
์ด ๋ค์ด์๋ค.
๊ฐ์ง ํ๋ก์ ๊ฐ์ฒด๋ ์ค์ request scope ์๋ ๊ด๊ณ๊ฐ ์๋ค. ๊ทธ๋ฅ ๊ฐ์ง์ด๊ณ , ๋ด๋ถ์ ๋จ์ํ ์์ ๋ก์ง๋ง ์๊ณ , ์ฑ๊ธํค
์ฒ๋ผ ๋์ํ๋ค.
์คํ๋ง์์๋ ํ๋ก์ ๊ฐ์ฒด๋ฅผ ์ฌ์ฉํ๊ธฐ ์ํด ๋น์ผ๋ก ํ๋ก์๋ฅผ ๋ง๋ค ์ ์๋ค.
โญ ๊ทธ ํ๋ก์๋ฅผ request scope ํ๋ก์
๋ผ๊ณ ํ๋ค.
request scope ํ๋ก์
๋, HTTP ์์ฒญ ๋จ์์ ์ค์ฝํ๋ฅผ ๊ฐ์ง๋ ๋น(Bean)์ ๋ํ ํ๋ก์ ๊ฐ์ฒด๋ฅผ ์๋ฏธํฉ๋๋ค.
์ด๋ฌํ ํ๋ก์ ๊ฐ์ฒด๋ ์ค์ ๋น์ด ์ฒ์ ์์ฒญ๋ ๋ ์์ฑ๋๋ฉฐ, ๊ทธ ํ์๋ ์์ฒญ์ ๋ํ ๋ชจ๋ ๋น์ ์ฐธ์กฐ๊ฐ ์ด ํ๋ก์ ๊ฐ์ฒด๋ก ์ ๋ฌ๋๋ค.
์ด ํ๋ก์ ๊ฐ์ฒด๋ ํด๋น ์์ฒญ ๋ฒ์ ๋ด์์ ๋น์ ์๋ช ์ฃผ๊ธฐ๋ฅผ ๊ด๋ฆฌํ๊ณ , ๋น์ด ์ค์ฝํ์์ ์ ๊ฑฐ๋ ๋ ํด๋น ๋น์ destroy() ๋ฉ์๋๋ฅผ ํธ์ถํ์ฌ ๋น์ด ์ ๋๋ก ์ข ๋ฃ๋๋๋ก ๋ณด์ฅํ๋ค.
์ด๋ฅผ ํตํด, Spring ์ ํ๋ฆฌ์ผ์ด์ ์์ Request scope ๋น์ ์ฝ๊ฒ ์ฌ์ฉํ ์ ์์ผ๋ฉฐ, ๋น์ด ์์ฒญ ๋ฒ์ ๋ด์์๋ง ์กด์ฌํ๊ณ ๋ค๋ฅธ ์์ฒญ์์๋ ์ฌ์ฌ์ฉ๋์ง ์๋๋ก ํ ์ ์๋ค.
CGLIB์ด๋ผ๋ ๋ฐ์ดํธ ์ฝ๋๋ฅผ ์กฐ์ํ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉ
ํด์ ํ๋ก์ ๊ฐ์ฒด๋ฅผ ์ฃผ์
ํด์ค๋ค.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๋ฅผ ์ฌ์ฉํ ์ ์๋ค.
์ฌ์ค Provider๋ฅผ ์ฌ์ฉํ๋ , ํ๋ก์๋ฅผ ์ฌ์ฉํ๋ ํต์ฌ ์์ด๋์ด๋ ์ง์ง ๊ฐ์ฒด ์กฐํ๋ฅผ ๊ผญ ํ์ํ ์์ ๊น์ง โ
์ง์ฐ์ฒ๋ฆฌ ํ๋ค๋ ์
์ด๋ค.
๋จ์ง ์ ๋ ธํ ์ด์ ์ค์ ๋ณ๊ฒฝ๋ง์ผ๋ก ์๋ณธ ๊ฐ์ฒด๋ฅผ ํ๋ก์ ๊ฐ์ฒด๋ก ๋์ฒดํ ์ ์๋ค. ์ด๊ฒ์ด ๋ฐ๋ก ๋คํ์ฑ๊ณผ DI ์ปจํ ์ด๋๊ฐ ๊ฐ์ง ํฐ ๊ฐ์ ์ด๋ค.
๊ผญ ์น์ค์ฝํ๊ฐ ์๋์ด๋ ํ๋ก์๋ ์ฌ์ฉํ ์ ์๋ค.
final
ํด๋์ค ๊ธฐ๋ฐ ํ๋ก์๋ ์์์ ์ฌ์ฉํ๊ธฐ ๋๋ฌธ์ ๋ช๊ฐ์ง ์ ์ฝ์ด ์๋ค.
์์ฑ์๋ฅผ ์ฒดํฌํด์ผ ํ๋ค.
CGLIB๋ ์์ ํด๋์ค๋ฅผ ๋์ ์ผ๋ก ์์ฑํ๊ธฐ ๋๋ฌธ์ ๊ธฐ๋ณธ์์ฑ์๊ฐ ํ์ํ๋ค.final ํค์๋
๊ฐ ๋ถ์ผ๋ฉด ์์์ด ๋ถ๊ฐ๋ฅํ๋ค. CGLIB์์ ์์ธ๊ฐ ๋ฐ์ํ๋ค.final ํค์๋
๊ฐ ๋ถ์ผ๋ฉด ํด๋น ๋ฉ์๋๋ฅผ ์ค๋ฒ๋ผ์ด๋ฉ ํ ์ ์๋ค. => CGLIB์์๋ ํ๋ก์ ๋ก์ง์ด ๋์ํ์ง ์๋๋ค.์ธํฐํ์ด์ค ์์ด๋ ํ๋ก์ ์์ฑ ๊ฐ๋ฅ
JDK ๋์ ํ๋ก์๋ ๋ฐ๋์ ์ธํฐํ์ด์ค๊ฐ ์์ด์ผ๋ง ๋์ํด. ๋ฐ๋ฉด CGLIB๋ ํด๋์ค๋ฅผ ์์ํด์ ํ๋ก์๋ฅผ ๋ง๋ค๊ธฐ ๋๋ฌธ์, ์ธํฐํ์ด์ค๊ฐ ์์ด๋ ํ๋ก์ ์์ฑ์ด ๊ฐ๋ฅํ์ง. ์์ฆ์ ์ธํฐํ์ด์ค ์์ด๋ ๋น์ ์ ์ํ๋ ๊ฒฝ์ฐ๊ฐ ๋ง์์ง๋ฉด์, CGLIB์ ์ ์ฐ์ฑ์ด ๋ ๋น์ ๋ฐํ๊ฒ ๋์ด.
์ฑ๋ฅ ๊ฐ์
์์ ์๋ CGLIB๊ฐ ์๋์ ์ผ๋ก ๋๋ฆฌ๋ค๊ณ ์ฌ๊ฒจ์ก์ง๋ง, JDK ํ๋ก์๋ ๋ฆฌํ๋ ์
๊ธฐ๋ฐ์ด๋ผ์ ์คํ๋ ค ์ฑ๋ฅ์ด ๋จ์ด์ง๋ ๊ฒฝ์ฐ๋ ์์ด. ํนํ ๋ฉ์๋ ํธ์ถ์ด ๋น๋ฒํ ๊ฒฝ์ฐ์ CGLIB๊ฐ ๋ ๋์ ์ฑ๋ฅ์ ๋ณด์ด๊ธฐ๋ ํด.
Spring Boot์ ์๋ ๊ตฌ์ฑ ์ฒ ํ๊ณผ ์ ๋ง์
์คํ๋ง ๋ถํธ๋ ๊ฐ๋ฐ์๊ฐ ์ธํฐํ์ด์ค๋ฅผ ๊ผญ ๋ง๋ค์ง ์์๋ ๋น ๋ฅด๊ฒ ๊ฐ๋ฐํ ์ ์๋๋ก ์ค๊ณ๋์์. ๊ทธ๋์ ์ธํฐํ์ด์ค ์ ๋ฌด์ ์๊ด์์ด ์ผ๊ด๋ ๋ฐฉ์์ผ๋ก ํ๋ก์๋ฅผ ์์ฑํ ์ ์๋ CGLIB๊ฐ ๋ ์์ฐ์ค๋ฌ์ด ์ ํ์ด ๋ ๊ฑฐ์ผ.
์์กด์ฑ ๋ฌธ์ ํด๊ฒฐ
์์ ์๋ CGLIB๊ฐ ์ธ๋ถ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์๊ธฐ ๋๋ฌธ์ ์ ๋ขฐ์ฑ์ด๋ ์์กด์ฑ ๊ด๋ฆฌ ์ธก๋ฉด์์ ๋ถ๋ด์ด ์์์ง๋ง, Spring 3.2๋ถํฐ๋ spring-core์ ๋ด์ฅ๋๋ฉด์ ์ด๋ฐ ๋ฌธ์ ๊ฐ ์ฌ๋ผ์ก์ด.
๋ฌผ๋ก ์ฌ์ ํ spring.aop.proxy-target-class=false
์ค์ ์ ํตํด JDK ํ๋ก์๋ก ๋ฐ๊ฟ ์๋ ์์ด. ํ์ง๋ง ์์ฆ์ ๋๋ถ๋ถ์ ๊ฒฝ์ฐ CGLIB๊ฐ ๋ ์ค์ฉ์ ์ด๋ผ ๊ธฐ๋ณธ๊ฐ์ผ๋ก ์๋ฆฌ ์ก์ ๊ฒ์ด๋ค.
Jpa ์กฐํ๊ธฐ๋ฅ ์ค lazy loading ์ ํตํด proxy๋ก ํธ์ถ
Advice
๋ ํ๋ก์์ ์ ์ฉํ๋ ๋ถ๊ฐ ๊ธฐ๋ฅ ๋ก์ง์ด๋ค.
์ด๊ฒ์ JDK ๋์ ํ๋ก์๊ฐ ์ ๊ณตํ๋ InvocationHandler
์
CGLIB๊ฐ ์ ๊ณตํ๋ MethodInterceptor
์ ๊ฐ๋
๊ณผ ์ ์ฌํ๋ค.
๋์ ๊ฐ๋
์ ์ผ๋ก ์ถ์ํ ํ ๊ฒ์ด๋ค. ํ๋ก์ ํฉํ ๋ฆฌ
๋ฅผ ์ฌ์ฉํ๋ฉด ๋ ๋์ ์ Advice
๋ฅผ ์ฌ์ฉํ๋ฉด ๋๋ค.
@Transactional
์๋
ธํ
์ด์
์ด ๋ํ์ ์ธ ์์์ธํ ๊ฑด ์ด ๋ธ๋ก๊ทธ ์ฐธ์กฐ
https://velog.io/@mooh2jj/์คํ๋ง-ํธ๋์ญ์
-AOP-์ดํด
@Transactional ์ ์ฌ์ฉํ๋ฉด ์คํ๋ง์ ํธ๋์ญ์
AOP๊ฐ ์ ์ฉ๋๋ค.
ํธ๋์ญ์
AOP๋ ๊ธฐ๋ณธ์ ์ผ๋ก ํ๋ก์(Proxy) ๋ฐฉ์
์ ์ฌ์ฉํ๋ค.
๊ฐ๋จํ ์ ๋ฆฌํ์๋ฉด,
@Transactional ์ ์ ์ฉํ๋ฉด ํ๋ก์ ๊ฐ์ฒด๊ฐ ์์ฒญ์ ๋จผ์ ๋ฐ์์(์์) ํธ๋์ญ์ ์ ๋์ ์ฒ๋ฆฌํ๊ณ , ์ค์ ๊ฐ์ฒด๋ฅผ ํธ์ถํด์ฃผ๋ ๊ฒ์ด๋ค.
์ด ๋ฐ์ @Cachable
, @Async
๋ ์๋ค.
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
* ๋ฉ์๋๋ง๋ค ์ ์ฉ
*/
@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
: ํด๋์ค์ AOP ์ค์ ์ ๋ถ์ฌ์ฃผ๋ ์ด๋
ธํ
์ด์
โจ JointPoint
: ํฉ๋ฅ ์ง์ , ๋ฉ์๋ ์คํ์์
- ํก๋จ ๊ณตํต(Crosscutting Concerns) ๋ชจ๋์ด ์ฝ์
๋์ด ๋์ํ ์ ์๋ ์คํ ๊ฐ๋ฅํ ํน์ ์์น
- ๋ฉ์๋ ํธ์ถ, ๋ฉ์๋ ์คํ ์์ฒด, ํด๋์ค ์ด๊ธฐํ, ๊ฐ์ฒด ์์ฑ ์์ ๋ฑ
โจPointcut
: ์ด๋ค ํฌ์ธํธ(Point)์ ๊ธฐ๋ฅ์ ์ ์ฉํ ์ง ํ์ง ์์์ง ์๋ผ์(cut) ๊ตฌ๋ถํ๋ ๊ฒ์ด๋ค.
- Pointcut์ ์ด๋ค ํด๋์ค์ ์ด๋ JoinPoint๋ฅผ ์ฌ์ฉํ ๊ฒ์ธ์ง๋ฅผ ๊ฒฐ์ ํ๋ ํํฐ ํจํด
โจ Around
: ๋์ ๋ฉ์๋์ ์คํ ์ ํ์ Aspect๊ฐ ์ ์ฉ๋ ์ ์๊ฒ ๋์์ค๋ค.
@Around
์ด๋๋ฐ์ด์ค๋ ๋์ ๋ฉ์๋์ ์คํ์ ๊ฐ์ธ์ ์ /ํ ์ฒ๋ฆฌ๋ฅผ ์ํํ ์ ์์ต๋๋ค.โจ Advice
: ํ๋ก์๊ฐ ํธ์ถํ๋ ์กฐ์ธ(๋ถ๊ฐ ๊ธฐ๋ฅ) ๋จ์ํ๊ฒ ํ๋ก์ ๋ก์ง์ด๋ผ ์๊ฐํ๋ฉด ๋๋ค.
- Advice๋ ๊ด์ (Aspect)์ ์ค์ ๊ตฌํ์ฒด๋ก ๊ฒฐํฉ์ ์ ์ฝ์
๋์ด ๋์ํ ์ ์๋ ์ฝ๋
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)
1) Before Advice : ํฌ์ธํธ์ปท์ผ๋ก ์ง์ ๋ ๋ฉ์๋๋ฅผ ํธ์ถ ์ ๋ฉ์๋๊ฐ ์คํ๋๊ธฐ ์ ์ ์ฒ๋ฆฌํ ๋ด์ฉ์ ๊ธฐ์ ํ๊ธฐ ์ํด ์ฌ์ฉ
2) After Returning Advice : ํฌ์ธํธ์ปท์ผ๋ก ์ง์ ๋ ๋ฉ์๋๊ฐ ์ ์์ ์ผ๋ก ์คํ๋๊ณ ๋์, ๋ฉ์๋ ์ํ ๊ฒฐ๊ณผ๋ก ์์ฑ๋ ๋ฐ์ดํฐ๋ฅผ ๋ฆฌํดํ๋ ์์ ์ ๋์. ๋น์ง๋์ค ๋ฉ์๋์ ๊ฒฐ๊ณผ๋ก ์ป์ ๊ฒฐ๊ณผ ๋ฐ์ดํฐ๋ฅผ ์ด์ฉํ์ฌ ์ฌํ ๋ก์ง์ ์ถ๊ฐํ ๋ ์ฌ์ฉ๋๋ค.
3) After Throwing Advice : ํฌ์ธํธ์ปท์ผ๋ก ์ง์ ํ ๋ฉ์๋๊ฐ ์คํ๋๋ค๊ฐ ์์ธ๊ฐ ๋ฐ์ํ๋ ์์ ์ ๋์. ์์ธ ์ฒ๋ฆฌ ์ด๋๋ฐ์ด์ค๋ฅผ ์ค์ ํ ๋ ์ฌ์ฉํ๋ค.
4) After Advice : ์์ธ ๋ฐ์ ์ฌ๋ถ์ ์๊ด์์ด ๋ฌด์กฐ๊ฑด ์ํ๋๋ ์ด๋๋ฐ์ด์ค๋ฅผ ๋ฑ๋กํ ๋ ์ฌ์ฉ.
5) Around Advice : ๋ค๋ฅธ Advice๋ ์คํ ์ /ํ์ ์ํ๋๋ ์ฒ๋ฆฌ๋ฅผ ์ํด์ ์ค์ ํ๋ค๋ฉด Around Advice๋ ํด๋ผ์ด์ธํธ์ ๋ฉ์๋ ํธ์ถ์ ๊ฐ๋ก์ฑ ๋ค ์คํ ์ /ํ์ ์ฒ๋ฆฌ๋ฅผ ๋์์ ์ฒ๋ฆฌํ ์ ์๋ค.