AOP(3) - Dynamic Proxy
๋ค์ด๋๋ฏน ํ๋ก์๋?
๋ฐํ์ ์์ ๋์ ์ผ๋ก ๋ง๋ค์ด์ง๋ ์ค๋ธ์ ํธ
java์ reflection์ ์ด์ฉํด์ proxy ๊ฐ์ฒด ์์ฑ(
java.lang.reflect
)ํ๊ฒ ์ธํฐํ์ด์ค์ ๋์ผํ ํํ๋ก ์์ฑ
ํ๋ก์ ๋์์ ๊ฐ์ฒด๊ฐ ์ต์ ํ๋ ์ด์์ ์ธํฐํ์ด์ค๋ฅผ ๊ตฌํํ๋ค๋ฉด JDK ๋์ ํ๋ก์๋ฅผ ์ด์ฉํ๋ฉด๋๋ค.
FactoryBean(ํฉํ ๋ฆฌ๋น)์ ํตํด ์์ฑ
reflection์ด๋ ๊ฐ์ฒด๋ฅผ ํตํด ํด๋์ค์ ์ ๋ณด๋ฅผ ๋ถ์ํด ๋ด๋ ํ๋ก๊ทธ๋จ ๊ธฐ๋ฒ์ ๋งํ๋ค.
์คํ๋ง์ ๋น์ ๊ธฐ๋ณธ์ ์ผ๋ก ํด๋์ค ์ด๋ฆ๊ณผ Property๋ก ์ ์ํ๋ค.
์คํ๋ง์ ์ง์ ๋ ํด๋์ค ์ด๋ฆ์ ๊ฐ์ง๊ณ reflection์ ์ด์ฉํด ํด๋น ํด๋์ค์ ๊ฐ์ฒด(object)๋ฅผ ์์ฑํ๋ค.

์คํ๋ง์์๋ JDK ๋์ ํ๋ก์์ CGLib ํ๋ก์๋ฅผ ์ฌ์ฉํ๊ณ ์๋ค.
JDK Dynamic Proxy
JDK Dynamic Proxy๋ Proxy Factory์ ์ํด ๋ฐํ์์ ๋์ ์ผ๋ก ๋ง๋ค์ด์ง๋ ์ค๋ธ์ ํธ์ด๋ค. JDK Dynamic Proxy๋ ๋ฐ๋์ ์ธํฐํ์ด์ค๊ฐ ์ ์๋์ด์๊ณ , ์ธํฐํ์ด์ค์ ๋ํ ๋ช ์ธ๋ฅผ ๊ธฐ์ค์ผ๋ก Proxy๋ฅผ ์์ฑํ๋ค. ์ฆ, ์ธํฐํ์ด์ค ์ ์ธ์ ๋ํ ๊ฐ์ ์ฑ์ด ์๋ค๋ ๋จ์ ์ด ์๋ค.
๋ด๋ถ์ ์ผ๋ก JDK Dynamic Proxy์์๋ InvationHandler๋ผ๋ ์ธํฐํ์ด์ค๋ฅผ ๊ตฌํํด ๋ง๋ค์ด์ง๋๋ฐ, invoke ํจ์๋ฅผ ์ค๋ฒ๋ผ์ด๋ฉํ์ฌ Proxy์ ์์ ๊ธฐ๋ฅ์ ์ํํ๋ค. ์ด ๊ณผ์ ์์ ๊ฐ์ฒด์ ๋ํ Reflection ๊ธฐ๋ฅ์ ์ฌ์ฉํด ๊ตฌํํ๊ธฐ ๋๋ฌธ์ ํผํฌ๋จผ์ค ํ๋ฝ์ ์์ธ์ด ๋๊ธฐ๋ ํ๋ค.
๊ตฌํ๊ณผ์
Proxy.newProxyInstance() ๋ฅผ ํตํ ํ๋ก์ ์์ฑ
Proxy.newProxyInstance() ํธ์ถํ ๋ ์ ๋ฌํ๋ InvocationHandler ์ธํฐํ์ด์ค์ ๋จ์ผ ๋ฉ์๋์ธ invoke()์ ๋ถ๊ฐ๊ธฐ๋ฅ์ ๋จ ํ๋ฒ๋ง ๊ตฌํํจ์ผ๋ก์จ ์ฝ๋ ์ค๋ณต์ ํด๊ฒฐํ ์ ์๋ค.
๋ค์ด๋๋ฏน ํ๋ก์ ๊ฐ์ฒด๋ ํด๋์ค ํ์ผ ์์ฒด๊ฐ ์กด์ฌํ์ง ์์ผ๋ฉฐ, ๋น ๊ฐ์ฒด๋ก ๋ฑ๋ก์ด ๋ถ๊ฐํ๋ค.
public interface ServiceTest {
void print();
}
@Service
public class ServiceTestImpl implements ServiceTest {
@Async
public void print() {
}
}
@RestController
public class HelloController {
private final ServiceTest service;
public HelloController(ServiceTest service) {
this.service = service;
System.out.println(service.getClass());
}
}
class com.sun.proxy.$Proxy60
์์ ์ฝ๋๋ฅผ ์ดํด๋ณด๋ฉด ์ธํฐํ์ด์ค(ServiceTest)๋ฅผ ๊ตฌํํ ๊ฐ์ฒด(ServiceTestImpl)์ด ์๋ค. print๋ฌธ์ ๊ฒฐ๊ณผ๋ฅผ ๋ณด๋ฉด JDK ๋์ ํ๋ก์๊ฐ ๋ค์ด๊ฐ ๊ฒ์ ํ์ธํ ์ ์๋ค.
์คํ๋ง AOP๋ฅผ ์ด์ฉํ์ฌ ํ๋ก์ ๊ฐ์ฒด๋ฅผ ์์ฑํด๋ณผ ๊ฒ์ด๋ค. ์คํ๋ง ๋ด๋ถ์์ ์ ๊ณตํ๋ FactoryBean ํด๋์ค๋ฅผ ์ฌ์ฉํ์ฌ ์์ฑํ ๊ฒ์ด๋ค.
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setInterfaces(ServiceTest.class);
proxyFactory.setTarget(new ServiceTestImpl());
proxyFactory.addAdvice(new ServiceAdvice());
final ServiceTest proxy = (ServiceTest) proxyFactory.getProxy();
System.out.println(proxy.getClass());
class com.sun.proxy.$Proxy60
์ธํฐํ์ด์ค๊ฐ ์์ด์ JDK ๋์ ํ๋ก์๊ฐ ์์ฑ๋ ๊ฒ์ ๋ณผ ์ ์๋ค.
CGLib Proxy
CGLIB Proxy๋ ์์ Java JDK ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ด์ฉํ๋ ๊ฒ์ด ์๋ CGLIB๋ผ๋ ์ธ๋ถ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ถ๊ฐํด์ผ๋ง ์ฌ์ฉํ ์ ์๋ค. CGLIB์ Enhancer ํด๋์ค๋ฅผ ๋ฐํ์ผ๋ก Proxy๋ฅผ ์์ฑํ๋ฉฐ, ์ธํฐํ์ด์ค๊ฐ ์์ด๋ Proxy๋ฅผ ์์ฑํ ์ ์๋ค. CGBLIB Proxy๋ ํ๊ฒ ํด๋์ค๋ฅผ ์์๋ฐ์ ์์ฑํ๊ธฐ ๋๋ฌธ์ Proxy๋ฅผ ์์ฑํ๊ธฐ ์ํด ์ธํฐํ์ด์ค๋ฅผ ๋ง๋ค์ด์ผํ๋ ์๊ณ ๋ฅผ ๋ ์ ์๋ค.
ํ์ง๋ง, ์์์ ์ด์ฉํ๋ฏ๋ก final์ด๋ private์ ๊ฐ์ด ์์์ ๋ํด ์ค๋ฒ๋ผ์ด๋ฉ์ ์ง์ํ์ง ์๋ ๊ฒฝ์ฐ์๋ Aspect๋ฅผ ์ ์ฉํ ์ ์๋ค๋ ๋จ์ ์ด ์๋ค.
CGLIB Proxy๋ ๋ฐ์ดํธ ์ฝ๋๋ฅผ ์กฐ์ํด์ ํ๋ก์ ๊ฐ์ฒด๋ฅผ ์์ฑํ๋ฏ๋ก JDK Dynamic Proxy๋ณด๋ค ํผํฌ๋จผ์ค๊ฐ ๋น ๋ฅธ ์ฅ์ ์ด ์๋ค.
@Service
public class ServiceTestImpl {
@Async
public void print() {
}
}
@RestController
public class HelloController {
private final ServiceTest service;
public HelloController(ServiceTest service) {
this.service = service;
System.out.println(service.getClass());
}
}
class me.wonwoo.ServiceTestImpl$$EnhancerBySpringCGLIB$$bababcc1
์ธํฐํ์ด์ค ์์ด ์์ฑํ ๊ฒฝ์ฐ์๋ CGLib ํ๋ก์๋ก ์์ฑ๋ ๊ฒ์ ํ์ธํ ์ ์๋ค.
์คํ๋ง AOP๋ฅผ ์ด์ฉํ์ฌ ํ๋ก์ ๊ฐ์ฒด๋ฅผ ์์ฑํด๋ณผ ๊ฒ์ด๋ค. ์คํ๋ง ๋ด๋ถ์์ ์ ๊ณตํ๋ FactoryBean ํด๋์ค๋ฅผ ์ฌ์ฉํ์ฌ ์์ฑํ ๊ฒ์ด๋ค.
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTarget(new ServiceTestImpl());
proxyFactory.addAdvice(new ServiceAdvice());
final ServiceTest proxy = (ServiceTest) proxyFactory.getProxy();
System.out.println(proxy.getClass());
class me.wonwoo.ServiceTestImpl$$EnhancerBySpringCGLIB$$bababcc1
์ธํฐํ์ด์ค ์์ด ์์ฑํ ๊ฒฝ์ฐ์๋ CGLib ํ๋ก์ ๊ฐ์ฒด๊ฐ ์์ฑ๋ ๊ฒ์ ๋ณผ ์ ์๋ค.
ํ๋ก์ ๊ฐ์ฒด์ CGLib์ ๊ฐ์ ํ ํ๊ณ ์ถ๋ค๋ฉด ๋ค์๊ณผ ๊ฐ์ด ์ค์ ํ ์ ์๋ค. ๊ฐ์ ํ๋ฅผ ํ๊ฒ๋๋ฉด ์ธํฐํ์ด์ค๊ฐ ์๋ ๊ฒฝ์ฐ์๋ CGLib ํ๋ก์ ๊ฐ์ฒด๊ฐ ์ฝ์ ๋๋ค.
@EnableAsync(proxyTargetClass = true)
@EnableCaching(proxyTargetClass = true)
JDK Dynamic Proxy vs CGLIB
๋ ๋ฐฉ์์ ์ฐจ์ด๋ ์ธํฐํ์ด์ค์ ์ ๋ฌด ๋ก์, AOP์ ํ๊ฒ์ด ๋๋ ํด๋์ค๊ฐ ์ธํฐํ์ด์ค๋ฅผ ๊ตฌํํ์๋ค๋ฉด JDK Dynamic Proxy ์ฌ์ฉ, ๊ตฌํํ์ง ์์๋ค๋ฉด CGLIB ๋ฐฉ์์ ์ฌ์ฉํ๋ค.
์ฌ์ฉ์๊ฐ ์ด๋ป๊ฒ ์ค์ ํ๋๋์ ๋ฐ๋ผ์ ์ธํฐํ์ด์ค๋ฅผ ๊ตฌํํ๋ค ํ๋๋ผ๋ CGLIB ๋ฐฉ์์ ๊ฐ์ ํ๊ฑฐ๋ AspectJ๋ฅผ ์ฌ์ฉํ ์ ์๋ค.
CGLIB(์คํ๋ง์ XML ์ค์ ํ์ผ์ ๋น์ ๋ฑ๋กํ๋ ๋ฐฉ๋ฒ)
<!--proxy-targetclass="true"์ ์ถ๊ฐํ์ฌ CGLIB์ ์ฌ์ฉํ๋๋ก ํ๋ค.-->
<aop:config proxy-target-class="true">
<!-- other beans defined here... -->
<aop:pointcut id="fooServiceMethods" expression="execution(* x.y.service.*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="fooServiceMethods"/>
</aop:config>
AspectJ : ์ด๋ ธํ ์ด์ ๊ธฐ๋ฐ์ ์คํ์ผ ์ ํธ
<aop:aspectj-autoproxy proxy-target-class="true">
์ฐธ์กฐ ํ์ด์ง
Last updated
Was this helpful?